. Net asynchronous mechanism for inter-thread Communication)

Source: Internet
Author: User

Inter-thread Communication

Let's look at the figure below

Figure 1

Let's look at the principle of inter-thread communication: thread B communicates with thread A. First, thread a must implement synchronous context object (synchronization context ), thread B accesses thread A by calling the synchronization context object of thread A. All implementations are completed in the synchronization context. thread B can communicate with each other in two ways.

First, call the synchronization context object of thread a to block the current thread. Execute the Red Arrow call and release the current thread until the yellow arrow returns (the synchronization context execution is complete. (1-> 2-> 3-> 5)

Second, execute the Red Arrow to call the synchronization context object of thread A (in fact, starting a new thread for execution, 1-> 2-> 3-> 5, but it does not hinder the current thread (the original thread, 1-> 4-> 5), and the Green Arrow continues to run.

ArticleThe following classes will be introduced:

1. isynchronizeinvoke Interface

2. synchronizationcontext class

3. asyncoperation/asyncoperationmanager class

1. isynchronizeinvoke Interface

Let's take a look at the following asynchronousCode(The Window Form Control has one button/one label), but when you click the button, run the asynchronous call. After the call is complete, tells the text attribute "Asynchronous end" of the label control of window form ".

Code1.1

1 delegate void dowork ();
2 Private void button#click (Object sender, eventargs E)
3 {
4 // auxiliary method to view the current thread
5 Debug. writeline (string. Format ("window form method. Thread ID: #{0 }",
Thread. currentthread. managedthreadid ));
6 // label lblstatus is the control of the main thread [1]
7 This. lblstatus. Text = "Asynchronous Start .";
8 // use a delegate to call an Asynchronous Method
9 dowork work = doworkmethod;
10 work. begininvoke (onworkcallback, work );
11}
12 Void onworkcallback (iasyncresult asyncresult)
13 {
14 // auxiliary method to view the current thread
15 Debug. writeline (string. Format ("Asynchronous callback method. Thread ID: #{0 }",
Thread. currentthread. managedthreadid ));
16 dowork work = asyncresult. asyncstate as dowork;
17 if (work! = NULL)
18 {
19 work. endinvoke (asyncresult );
20}
21 // error: "The Inter-thread operation is invalid: It is accessed by a thread that is not creating the control" lblstatus ."
22 This. lblstatus. Text = "Asynchronous end"; // note [1]
23}
24
25 void doworkmethod ()
26 {
27 thread. Sleep (3000); // simulate time-consuming work
28}

Run the code and we will report an error in line 3 (Asynchronous Method body). Why? We must be clear that the windows application form applicationProgram. Methods and properties of controls cannot be securely accessed from other threads. We can also see from the debug window (Figure 1.1 ). when the button click event is executed, it runs in thread id = #10; In the Asynchronous Method body, it runs in thread id = #7. different threads cannot communicate directly.

Fig 1.1

To solve this problem, implement the communication between #10 and #7 in Figure 1.1, and get to know the isynchronizeinvoke interface (this interface comes from. NET Framework 1.0) and provide three methods and one attribute:

Begininvoke/endinvoke method: Asynchronous Method

Invoke method: synchronous method

Invokerequired attribute: The execution thread that interprets the source

Next we will take a look at the specific code of code1.2 to explain (rewrite code1.1, where label is changed to ListBox)

Code1.2

1 delegate void dowork ();
2 Private void button#click (Object sender, eventargs E)
3 {
4 // update the status and add it to ListBox
5 addvalue ("Asynchronous Start .");
6 // use a delegate to call an Asynchronous Method
7 dowork work = doworkmethod;
8 work. begininvoke (onworkcallback, work );
9}
10
11 void onworkcallback (iasyncresult asyncresult)
12 {
13 dowork work = asyncresult. asyncstate as dowork;
14 if (work! = NULL)
15 {
16 work. endinvoke (asyncresult );
17}
18 // (1) method: Call the invoke of the Control
19 // action <string> asyncupdatestate = updatestatus; // action <string> description => Appendix 1
20 // invoke (asyncupdatestate, "1: asynchronous end .");
21
22 // (2) method: directly under the thread of asynchronous call
23 updatestatus ("2: asynchronous end .");
24}
25
26 void updatestatus (string input)
27 {
28 // assign the control you want to notify to isynchronizeinvoke
29 // to implement inter-thread Communication
30 isynchronizeinvoke async = This. listboxstatus;
31 // use (1) method, invokerequired = false, source current (window form) main thread
32 If (async. invokerequired = false)
33 addvalue (input );
34 else // use (2) Method = true, source other threads (asynchronous)
35 {
36 action <string> action = new action <string> (status =>
37 {
38 addvalue (Status );
39 });
40 // call the invoke synchronization method provided by isynchronizeinvoke to block the thread until the call ends
41 // you can also call the asynchronous begininvoke/endinvoke method provided by isynchronizeinvoke.
42 async. Invoke (action, new object [] {input });
43}
44}
45
46 void addvalue (string input)
47 {
48 This. listboxstatus. items. add (string. format ("[(# {2}) {0}] context is null: {1}", input, thread. currentcontext = NULL, thread. currentthread. managedthreadid ));
49}
50 void doworkmethod ()
51 {
52 thread. Sleep (3000); // simulate time-consuming work
53}

Fig 1.2

In the code (in the updatestatus method), we can see that it is mainly in isynchronizeinvoke async = This. listboxstatus; implements inter-thread communication. msdn explains that "the object implementing this interface can receive notifications about events and respond to queries about these events ". the ListBox control in window form (main thread) and the channel from Asynchronous Method (another thread) are established. invokerequired is used to determine the thread source. If the (1) method is used and the invoke method from the control of window form itself is used, invokerequired returns false. if the source is another thread (asynchronous) returns true. at the same time, isynchronizeinvoke provides asynchronous (begininvoke + endinvok) and synchronous method (invoke) to implement inter-thread communication. invoke is the first type/begininvoke + endinvok shown in Figure 1 at the top.

Appendix 1: Action <t…> /Func (T ..., Tresult) (simply put, "simplified delegation") can be seen in the introduction of msdn.

Action <t…> : Http://msdn.microsoft.com/zh-cn/library/018hxwa8.aspx

Func (T ..., Tresult): http://msdn.microsoft.com/zh-cn/library/bb549151.aspx

Code1.2 implements inter-thread communication. Looking back at the interpretation in Figure 1, "thread a must first implement the synchronization context object (synchronization context )", in code1.2, context objects are not implemented for the window form (main thread). If this object is not implemented, everything is not true. so what does window form do?

Let's look at the following code (using the console program ):

Code1.3

1 static class Program
2 {
3 static void main ()
4 {
5 // 1. Run the command in the main thread to view the thread ID and synchronization context.
6 console. writeline ("0. threadid: # {1}, synchronization context is null? {0 }",
7 synchronizationcontext. Current = NULL, thread. currentthread. managedthreadid );
8
9 // 2, run in the main thread, instantiate the Null Object test, view the thread ID and synchronization Context
10 Test A = new test ();
11 console. writeline ("1. threadid: # {1}, synchronization context is null? {0 }",
12 synchronizationcontext. Current = NULL, thread. currentthread. managedthreadid );
13
14 // 3, run in the main thread, instantiate the formtest object (inheriting the form), view the thread ID and synchronization Context
15 formtest test = new formtest ();
16 console. writeline ("2. threadid: # {1}, synchronization context is null? {0 }",
17 synchronizationcontext. Current = NULL, thread. currentthread. managedthreadid );
18
19 // 4. Run the command in the new thread to view the thread ID and synchronization context.
20 new thread (work). Start ();
21
22 console. Read ();
23}
24 static void work ()
25 {
26 console. writeline ("3. threadid: # {1}, synchronization context is null? {0 }",
27 synchronizationcontext. Current = NULL, thread. currentthread. managedthreadid );
28}
29}
30 public class formtest: system. Windows. Forms. FORM {}
31 public class test {}

Fig 1.3

We can see from the code and figure (synchronizationcontext. current = NULL to determine whether the synchronization context object exists), instantiate the formtest object (Inheriting System. windows. forms. form), form creates a synchronization context object for us by default, so that the main thread #9 has a synchronization context object, which is why code1.2 does not need to declare a synchronization context object, it also tells us that when a new thread is started #10, the thread itself has no synchronization context object.

2. synchronizationcontext class

Compared with the isynchronizeinvoke interface, the synchronizationcontext class (from.. NET Framework 2.0) provides more methods to operate the synchronization context object and implement inter-thread communication. in the preceding example, the synchronizationcontext class is implemented by the post/send method.

After decompiling, we can see:

Code2.1

1 Public Virtual void post (sendorpostcallback D, object state)
2 {
3 threadpool. queueuserworkitem (New waitcallback (D. Invoke), State );
4}
5
6 Public Virtual void send (sendorpostcallback D, object state)
7 {
8 d (State );
9}

Send = synchronous call of invoke in isynchronizeinvoke. First in Figure 1

Post = begininvoke + endinvoke asynchronous call in isynchronizeinvoke. The second type in Figure 1

Rewrite code1.2 code (or program in winform ).

Code2.2

1 delegate void dowork ();
2 Private void button#click (Object sender, eventargs E)
3 {
4 // system. Windows. Forms. Form automatically creates the default synchronization context object,
5 // directly obtain the current synchronization context object
6 synchronizationcontext context = synchronizationcontext. Current;
7 // update the status and add it to ListBox
8 addvalue <string> ("Asynchronous Start .");
9 // use a delegate to call an Asynchronous Method
10 dowork work = doworkmethod;
11 Work. begininvoke (onworkcallback, context );
12
13}
14 void onworkcallback (iasyncresult asyncresult)
15 {
16 asyncresult async = (asyncresult) asyncresult;
17 dowork work = (dowork) async. asyncdelegate;
18 work. endinvoke (asyncresult );
19
20 // Update Status
21 updatestatus ("Asynchronous end.", asyncresult. asyncstate );
22}
23 void updatestatus (Object input, object synccontext)
24 {
25 // obtain the synchronization context object in the main thread (window form)
26 synchronizationcontext context = synccontext as synchronizationcontext;
27 // use the asynchronous POST method in the synchronizationcontext class
28 sendorpostcallback callback = new sendorpostcallback (P => {
29 addvalue <Object> (P );
30 });
31 context. Post (callback, input); // post is asynchronous, send is synchronous
32
33}
34 void addvalue <t> (T input)
35 {
36 This. listboxstatus. items. add (string. format ("[(# {2}) {0}] context is null: {1}", input, thread. currentcontext = NULL, thread. currentthread. managedthreadid ));
37}
38 void doworkmethod ()
39 {
40 thread. Sleep (3000); // simulate time-consuming work
41}

As we have mentioned above, in the main thread, system. windows. forms. form automatically creates the default synchronization context object. At this time, we assign the current synchronization context object to the asynchronous thread in the form of parameters and call the POST method for implementation, the post method receives sendorpostcallback delegation and additional object state parameters, and calls the thread pool thread in the POST method (code2.1 ). of course, we can also directly use the send method.

Next let's look at the code in the thread (programming in the console ).

Code2.3

1 static class Program
2 {
3 static void main ()
4 {
5 output ("main thread start .");
6 // create synchronization context for the main thread
7 var context = new synchronizationcontext ();
8 // start a new thread
9 thread threadb = new thread (work );
10 threadb. Start (context );
11
12 console. Read ();
13}
14 static void work (object context)
15 {
16 output ("thread B ");
17
18 // obtain the synchronization context object in the main thread
19 synchronizationcontext SC = context as synchronizationcontext;
20
21 // asynchronously communicates with the main thread and sends "Hello World ".
22 SC. Post (New sendorpostcallback (P =>
23 {
24 output (P );
25}), "Hello World ");
26}
27 static void output (object value)
28 {
29 console. writeline ("[threadid: # {0}] {1}", thread. currentthread. managedthreadid, value );
30}
31}

Fig 2.3

Because there is no synchronization context object in the main thread, we start with the new synchronizationcontext (); object, which is basically the same as code2.2. from Figure 2.3, we can explain the second call in figure 1, which also shows that post is enabled for running a new thread (thread pool.

3. asyncoperation/asyncoperationmanager class

The asyncoperation/asyncoperationmanager class further encapsulates and implements the synchronizationcontext class. asyncoperationmanager obtains the synchronization context object of the current thread when creating the asyncoperation object and stores it in asyncoperation, this makes it easier for us to access the synchronization context object.

Code3.1

1 public class mysynchronizedclass
2 {
3 private asyncoperation operation;
4 public event eventhandler somethinghappened;
5 Public mysynchronizedclass ()
6 {
7 // create an asyncoperation object and keep the synchronization context of the current thread in asyncoperation.
8 Operation = asyncoperationmanager. createoperation (null);
9
10 thread workerthread = new thread (New threadstart (dowork);
11 workerthread. start ();
12}
13
14 private void dowork ()
15 {
16 sendorpostcallback callback = new sendorpostcallback (State =>
17 {
18 eventhandler handler = somethinghappened;
19
20 if (handler! = NULL)
21 {
22 handler (this, eventargs. empty);
23}
24});
25
26 operation. post (callback, null);
27 // Note 1
28 operation. operationcompleted ();
29}
30}

The code is very simple and I will not explain it. You can refer to all the code above. NOTE 1: The operationcompleted method is implemented in the asyncoperation class. The method in the synchronizationcontext class has no specific code implementation.

Summary:

In this article, synchronizationcontext is also very suitable for Thread Programming (except asynchronous) to implement communication. synchronizationcontext is the most important one. Other extension classes, such as synchronizationcontextswitcher and other more advanced topics, for more information, see the following link. there is a very important backgroundworker class in winform. Many articles about backgroundworker are not explained here.

<End>

I would like to thank the original author for writing such a wonderful and easy-to-understand article.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.