The Operation Cannot Be Completed Because the Dbcontext Has Been Disposed Error

Non-Blocking read from standard I/O in C#

var buf=new byte[2048];
var inputStream=Console.OpenStandardInput(); //dispose me when you're done
inputStream.BeginRead(buf,0,buf.Length,ar=>{
int amtRead=inputStream.EndRead(ar);
//buf has what you need. You'll need to decode it though
},null);

Non-blocking read of a byte from stdin

Provided your platform has an implementation of System.Collections.Concurrent.BlockingCollection, here's one easy if not exactly efficient way to do it:

class ConsoleReader {
private readonly BlockingCollection<int> buffer = new BlockingCollection<int>(1);
private readonly Thread readThread;
public ConsoleReader() {
readThread = new Thread(() => {
if (Console.IsInputRedirected) {
int i;
do {
i = Console.Read();
buffer.Add(i);
} while (i != -1);
} else {
while (true) {
var consoleKeyInfo = Console.ReadKey(true);
if (consoleKeyInfo.KeyChar == 0) continue; // ignore dead keys
buffer.Add(consoleKeyInfo.KeyChar);
}
}
});
}

public void Start() {
readThread.Start();
}

public int? Next {
get {
int result;
return buffer.TryTake(out result, 0) ? result : default(int?);
}
}
}

Disclaimer: this answer has not actually been tested on Mono, and only briefly on the full .NET platform.
You can spice this up with a Task instead of a Thread, proper cancellation etc., but that won't change the central inefficiency of explicitly waiting on a synchronous operation (which Console.Read and Console.ReadKey both are). Portable asynchronous console I/O is not offered by .NET itself. Implementing that yourself across platforms (using the OS features) is possible, but decidedly nontrivial.

Non-blocking way to check if a StreamReader has data available

OK, let me just say that I don't really know what you are trying to accomplish here. However, from what I can see, the Peek method has to block the current thread in order to work. This is what the documentation says:

The Peek method returns an integer value in order to determine whether
the end of the file, or another error has occurred. This allows a user
to first check if the returned value is -1 before casting it to a Char
type.

So, Peek should only return -1 if it encounters an error or end of the file. This is a little confusing, because there may be no file involved. The stream might be a response from a WebRequest, in which case, the part of the stream that you're trying to read might not be downloaded yet. So, Peek has to wait until it's done because, and this is not clear from the documentation, it returns the first byte read from the stream.

The problems that are mentioned in the links you posted are concerned with multiple threads using the same StreamReader, which is not your case. I also believe that there used to be a bug that would cause one StreamReader waiting for input to block another, but I believe it has since been fixed. I'm not sure what the Mono implementation does.

To answer your question, to do this without blocking the thread, I would try the following:

  1. Just put the whole thing into a separate thread. Then you won't care if it's blocked or not.
  2. Use ReadAsync and then await or ContinueWith on the task to make it non-blocking.

However, as was correctly remarked in the comments, if you put the whole thing into another thread, do you really need Peek? Why not just put it into your typical while (Read(...)) { ... } block and process the data as it's coming?

Non-blocking console input C++

I would do this by creating separate a thread which calls normal blocking IO functions and pass it a callback function which it would call when it got input. Are you sure you need to do what you said you want to do?

As for outputting information at the same time, what would happen if the user was in the middle of typing some input and you printed something?

capture keystroke without blocking

Have you read MSDN Key press info for console?

You can use Console.KeyAvailable to determine if you actually want to get the key in the queue.

Non-blocking read of stdin?

Use vbAdvance add-in to compile following sample with "Build As Console Application" option checked.

Option Explicit

'--- for GetStdHandle
Private Const STD_INPUT_HANDLE As Long = -10&
Private Const STD_OUTPUT_HANDLE As Long = -11&
'--- for PeekConsoleInput
Private Const KEY_EVENT As Long = 1
'--- for GetFileType
Private Const FILE_TYPE_PIPE As Long = &H3
Private Const FILE_TYPE_DISK As Long = &H1

Private Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
Private Declare Function GetConsoleMode Lib "kernel32" (ByVal hConsoleHandle As Long, lpMode As Long) As Long
Private Declare Function SetConsoleMode Lib "kernel32" (ByVal hConsoleHandle As Long, ByVal dwMode As Long) As Long
Private Declare Function PeekNamedPipe Lib "kernel32" (ByVal hNamedPipe As Long, lpBuffer As Any, ByVal nBufferSize As Long, ByVal lpBytesRead As Long, lpTotalBytesAvail As Long, ByVal lpBytesLeftThisMessage As Long) As Long
Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, ByVal lpOverlapped As Long) As Long
Private Declare Function OemToCharBuff Lib "user32" Alias "OemToCharBuffA" (ByVal lpszSrc As String, ByVal lpszDst As String, ByVal cchDstLength As Long) As Long
Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Any) As Long
Private Declare Function CharToOemBuff Lib "user32" Alias "CharToOemBuffA" (ByVal lpszSrc As String, lpszDst As Any, ByVal cchDstLength As Long) As Long
Private Declare Function PeekConsoleInput Lib "kernel32" Alias "PeekConsoleInputA" (ByVal hConsoleInput As Long, lpBuffer As Any, ByVal nLength As Long, lpNumberOfEventsRead As Long) As Long
Private Declare Function ReadConsoleInput Lib "kernel32" Alias "ReadConsoleInputA" (ByVal hConsoleInput As Long, lpBuffer As Any, ByVal nLength As Long, lpNumberOfEventsRead As Long) As Long
Private Declare Function GetFileType Lib "kernel32" (ByVal hFile As Long) As Long

Sub Main()
Dim hStdIn As Long
Dim sBuffer As String
Dim dblTimer As Double

hStdIn = GetStdHandle(STD_INPUT_HANDLE)
Do
sBuffer = sBuffer & ConsoleReadAvailable(hStdIn)
If dblTimer + 1 < Timer Then
dblTimer = Timer
Call OemToCharBuff(sBuffer, sBuffer, Len(sBuffer))
ConsolePrint "%1: %2" & vbCrLf, Format$(Timer, "0.00"), sBuffer
sBuffer = vbNullString
End If
Loop
End Sub

Private Function ConsoleReadAvailable(ByVal hStdIn As Long) As String
Dim lType As Long
Dim sBuffer As String
Dim lChars As Long
Dim lMode As Long
Dim lAvailChars As Long
Dim baBuffer(0 To 512) As Byte
Dim lEvents As Long

lType = GetFileType(hStdIn)
If lType = FILE_TYPE_PIPE Then
If PeekNamedPipe(hStdIn, ByVal 0, 0, 0, lAvailChars, 0) = 0 Then
Exit Function
End If
End If
If lType = FILE_TYPE_DISK Or lAvailChars > 0 Then
sBuffer = Space(IIf(lAvailChars > 0, lAvailChars, 512))
Call ReadFile(hStdIn, ByVal sBuffer, Len(sBuffer), lChars, 0)
ConsoleReadAvailable = Left$(sBuffer, lChars)
End If
If GetConsoleMode(hStdIn, lMode) <> 0 Then
Call SetConsoleMode(hStdIn, 0)
Do While PeekConsoleInput(hStdIn, baBuffer(0), 1, lEvents) <> 0
If lEvents = 0 Then
Exit Do
End If
If baBuffer(0) = KEY_EVENT And baBuffer(4) <> 0 Then ' baBuffer(4) = INPUT_RECORD.bKeyDown
sBuffer = Space(1)
Call ReadFile(hStdIn, ByVal sBuffer, Len(sBuffer), lChars, 0)
ConsoleReadAvailable = ConsoleReadAvailable & Left$(sBuffer, lChars)
Else
Call ReadConsoleInput(hStdIn, baBuffer(0), 1, lEvents)
End If
Loop
Call SetConsoleMode(hStdIn, lMode)
End If
End Function

Public Function ConsolePrint(ByVal sText As String, ParamArray A() As Variant) As String
' Const FUNC_NAME As String = "ConsolePrint"
Dim lI As Long
Dim sArg As String
Dim baBuffer() As Byte
Dim dwDummy As Long

'--- format
For lI = UBound(A) To LBound(A) Step -1
sArg = Replace(A(lI), "%", ChrW$(&H101))
sText = Replace(sText, "%" & (lI - LBound(A) + 1), sArg)
Next
ConsolePrint = Replace(sText, ChrW$(&H101), "%")
'--- output
ReDim baBuffer(1 To Len(ConsolePrint)) As Byte
If CharToOemBuff(ConsolePrint, baBuffer(1), UBound(baBuffer)) Then
Call WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), baBuffer(1), UBound(baBuffer), dwDummy, ByVal 0&)
End If
End Function

How redirect StandardInput on Process without process immediately exiting?

The problem is likely that you are using Console.ReadKey() in your lockfile.exe application. This does not accept input from standard input but uses low-level keyboard hooks to check for key presses which you cannot send from another application.

I tested your program with a LockFile.exe that just contained a simple Console.ReadLine(), and it works just as expected if I change the Write('X') call to a WriteLine("X") (since the call to readline needs a newline before returning). So I'm suspecting your problem is in the lockfile.exe program rather than this one. Ensure you are using Console.ReadLine() to wait for input from standard input in your lockfile.exe application.

C#: Read on subprocess stdout blocks until ANOTHER subprocess finishes?

I think it's not your code that's the issue. Blocking calls can unblock for a number of reasons, not only because their task was accomplished.

I don't know about Windows, I must admit, but in the Unix world, when a child finishes, a signal is sent to the parent process and this wakes him from any blocking calls. This would unblock a read on whatever input the parent was expecting.

It wouldn't surprise me if Windows worked similarly. In any case, read up on the reasons why a blocking call may unblock.



Related Topics



Leave a reply



Submit