Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

in C#, there are two threads when I call BeginXXX

I know something about the IOCP, but I'm a little confused with APM.

static FileStream fs;
static void Main(string[] args)
{
    fs = new FileStream(@"c:\bigfile.txt", FileMode.Open);
    var buffer = new byte[10000000];
    IAsyncResult asyncResult = fs.BeginRead(buffer, 0, 10000000, OnCompletedRead, null);
    Console.WriteLine("async...");
    int bytesRead = fs.EndRead(asyncResult);
    Console.WriteLine("async... over");
}

static void OnCompletedRead(IAsyncResult ar)
{
       Console.WriteLine("finished");
}

I wonder, is the read action executed by an IO thread asynchronously? Or a worker thread in a thread pool?

And the callback function OnCompletedRead, is it also executed by an IO thread in CLR thread pool?

Are these two threads the same one? If not, there are two threads generated, one executes the read action and another does the callback.

like image 825
roast_soul Avatar asked Aug 04 '14 15:08

roast_soul


People also ask

What does != Mean in C?

The not-equal-to operator ( != ) returns true if the operands don't have the same value; otherwise, it returns false .

What is '~' in C programming?

In mathematics, the tilde often represents approximation, especially when used in duplicate, and is sometimes called the "equivalency sign." In regular expressions, the tilde is used as an operator in pattern matching, and in C programming, it is used as a bitwise operator representing a unary negation (i.e., "bitwise ...

What is operators in C?

C operators are one of the features in C which has symbols that can be used to perform mathematical, relational, bitwise, conditional, or logical manipulations. The C programming language has a lot of built-in operators to perform various tasks as per the need of the program.

What is the use of in C?

In C/C++, the # sign marks preprocessor directives. If you're not familiar with the preprocessor, it works as part of the compilation process, handling includes, macros, and more.


2 Answers

If you don't use an AsyncCallback argument with BeginRead then there is only one thread that runs code in your program. This uses IO completion ports to signal when the IO is complete by running a small amount of code on a thread in the IO thread pool to update the status of the operation as being complete. When you call EndRead it will block the current thread until the IO operation is complete. It is asynchronous in that when you start the read operation the current thread does not need to do anything other than wait for the IO hardware to perform the read operation, so you can do other things in the meantime and then decide when you want to stop and wait for the IO to finish.

If you do pass in an AsyncCallback then when the IO operation is complete it will execute a small amount of code on an IO thread pool thread which will trigger your callback method to be executed on a thread from the .NET thread pool.

like image 152
mclaassen Avatar answered Oct 26 '22 03:10

mclaassen


Usually, mclaassen is right about the nature of IO bound work, IOCP and the APM. When BeginRead executes, it does so asynchronously all the way down to kernel mode. But, there is one caveat specifically in your example that he didn't mention in his answer.

In your example, you use the FileStream class. One important thing to note is that if you dont use the FileStream overload that accepts a useAsync boolean, when you invoke a BeginWrite / EndWrite operation, it will queue work on a new ThreadPool thread.

This is the proper overload:

public FileStream(
    string path,
    FileMode mode,
    FileAccess access,
    FileShare share,
    int bufferSize,
    bool useAsync
)

From MSDN:

useAsync:

Type: System.Boolean

Specifies whether to use asynchronous I/O or synchronous I/O. However, note that the underlying operating system might not support asynchronous I/O, so when specifying true, the handle might be opened synchronously depending on the platform. When opened asynchronously, the BeginRead and BeginWrite methods perform better on large reads or writes, but they might be much slower for small reads or writes. If the application is designed to take advantage of asynchronous I/O, set the useAsync parameter to true. Using asynchronous I/O correctly can speed up applications by as much as a factor of 10, but using it without redesigning the application for asynchronous I/O can decrease performance by as much as a factor of 10.

You have to make sure each specific method implementing the APM pattern truly uses true asynchronous work all the way down.

like image 32
Yuval Itzchakov Avatar answered Oct 26 '22 02:10

Yuval Itzchakov