Invokerequired and invoke

Source: Internet
Author: User

In. net, the access update of the control can only be executed on the thread that "owns" The control. Otherwise, an exception is thrown back.

Ms provides an invokerequired attribute in the control class. The following is a description of this attribute by msdn. I only have the Chinese version here. Whow.

Control. invokerequired attributes

Gets a value that indicates whether the caller must call the invoke method when calling the control method, because the call orientation is in a thread other than the thread where the control is created.

I have checked the comments in the English version. Both Chinese and English have emphasized that the control can only be called on the thread where the control is created. But this is not actually the case.

Correctly speaking, there are two concepts: creating a control thread and a control-owning thread. For the word "have", here is just my own yy. I hope I can explain the problem and I will explain it more later.

The thread for creating controls is easy to understand. What is the thread with controls. Are the two the same? Different.

The thread that owns the control. I am referring to the thread that created the handle control, rather than the thread that created the control. The two can be the same or different.

Then how does the thread create the handle of a control? It's easy. Let's take a look at the description of handle on msdn.

Control. Handle attributes

Obtain the window handle bound to the control.

Remarks
The handle attribute value is Windows hwnd. If the handle has not been created, referencing this property will force the creation of the handle.

In reality, when a control is created, its handle is not yet created. It is created only after it is referenced for the first time.

Below is a piece of code I wrote.

Using system;
Using system. Collections. Generic;
Using system. componentmodel;
Using system. Data;
Using system. drawing;
Using system. text;
Using system. Windows. forms;
Using system. Threading;

Namespace invokerequireddemo
{
Public partial class form1: Form
{
Control controlcreatedfromotherthread;

Public form1 ()
{
Initializecomponent ();
}

Private void form1_load (Object sender, eventargs E)
{
Thread createcontrolthread = new thread (
New threadstart (createcontrolinstance ));
Createcontrolthread. Start ();

While (null = controlcreatedfromotherthread)
{
Thread. Sleep (100 );
}

MessageBox. Show (controlcreatedfromotherthread. invokerequired. tostring ());
}

Private void createcontrolinstance ()
{
Control newcontrolinstance = new control ();
Controlcreatedfromotherthread = newcontrolinstance;
}
}
}

When you run this code, the dialog box throws false. It indicates that the main thread can call the update control, although this control is created in another thread.

Next let's change the createcontrolinstance () method.

Private void createcontrolinstance ()
{
Control newcontrolinstance = new control ();
Intptr = newcontrolinstance. Handle;
Controlcreatedfromotherthread = newcontrolinstance;
}

We added an intptr = newcontrolinstance in the code. handle; this Code allows the thread (not the main thread) of the control to access the handle of the control. After the code is changed, it is run. The dialog box throws true.

There is another interesting thing about control. Handle. For example, in the above Code, you asked the thread that created the control to create its handle at the same time, and then return to the main thread. At this time, what will happen if you try to access its handle?

Private void form1_load (Object sender, eventargs E)
{
Thread createcontrolthread = new thread (
New threadstart (createcontrolinstance ));
Createcontrolthread. Start ();

While (null = controlcreatedfromotherthread)
{
Thread. Sleep (100 );
}
MessageBox. Show (controlcreatedfromotherthread. Handle. tostring ());
}

The answer is to throw an exception. The Inter-thread operation is invalid: It is never accessed by the thread that creates the control.

Modify the code again:

Public Delegate void sampledelegate ();

Private void form1_load (Object sender, eventargs E)
{
Thread createcontrolthread = new thread (
New threadstart (createcontrolinstance ));
Createcontrolthread. Start ();

While (null = controlcreatedfromotherthread)
{
Thread. Sleep (100 );
}

Sampledelegate = new sampledelegate (samplemethod );
Controlcreatedfromotherthread. Invoke (
Sampledelegate );
}

Public void samplemethod ()
{

// Nothing to do

// Please try to make a breakpoint here.

// In this case, no stack here when run the demo.
}

Run, you will find that the Code has not gone into samplemethod (), it is strange that the result I tried at the company is directly in controlcreatedfromotherthread. throwing an exception on invoke (nullreference, but we know that controlcreatedfromotherthread is not empty ). Maybe the framework or IDE is different. Is the company vs2005? C # Express? Vs2008 is used at home.

Change controlcreatedfromotherthread. invoke to this. invoke, and samplemethod () can be used.

I guess that when invoke is used, it is necessary to find the thread with Control Based on handle, and then call the proxy method in this thread, the above code throws an exception because the main thread cannot get handle and is null.

Finally, let's talk about when the handle will be created. On msdn, it indicates that it will be created when it is referenced. When will it be referenced? Direct Control. Handle. Of course, there are other cases.

For example, if you add a control to the form, the handle of the control will also be created by the thread where the form is located. In fact, if the control and the form handle are not in the same thread, you cannot add it to the form. For example:

Private void form1_load (Object sender, eventargs E)
{
Thread createcontrolthread = new thread (
New threadstart (createcontrolinstance ));
Createcontrolthread. Start ();

While (null = controlcreatedfromotherthread)
{
Thread. Sleep (100 );
}

This. Controls. Add (controlcreatedfromotherthread );
}

In vs2008, "Inter-thread operation is invalid: access from a thread that is not creating the control ." . The exception thrown at the company is more detailed, probably that is, the control cannot be added to the form, because their handle is not in the same pub.

Let's look at the following example:

Private void form1_load (Object sender, eventargs E)
{
Thread createcontrolthread = new thread (
New threadstart (createcontrolinstance ));
Createcontrolthread. Start ();

While (null = controlcreatedfromotherthread)
{
Thread. Sleep (100 );
}

This. Controls. Add (controlcreatedfromotherthread );
}

Private void createcontrolinstance ()
{
Control newcontrolinstance = new control ();

Form newform = new form ();
Newform. Controls. Add (newcontrolinstance );

Controlcreatedfromotherthread = newcontrolinstance;
}

Note that a new form is created in createcontrolinstance and the newly created control is added to the form. However, the handle of the control is not actually created at this time, and we run the code, there will be no exceptions. This is because the new form has not been shown.

Then change:

Private void createcontrolinstance ()
{
Control newcontrolinstance = new control ();

Form newform = new form ();
Newform. Controls. Add (newcontrolinstance );
Newform. Show ();

Controlcreatedfromotherthread = newcontrolinstance;
}

Add newform. Show () and run it again. The exception is thrown. The handle of the new control is also created along with the show of the form. The show method should first create the handle of the form, and then create the handle of the face control.

In addition, different threads in the same process share the same heap, that is, they can share a piece of memory. But why cannot different threads share the control's handle? I Guess ms is doing this specially, because if handle is shared, a deadlock may easily occur in a multi-threaded environment.

Control controlcreatedfromotherthread;
Intptr controlintptrfromotherthread;

Private void form1_load (Object sender, eventargs E)
{
Thread createcontrolthread = new thread (
New threadstart (createcontrolinstance ));
Createcontrolthread. Start ();

While (intptr. Zero. Equals (controlintptrfromotherthread ))
{
Thread. Sleep (100 );
}

Controlcreatedfromotherthread = control. fromhandle (controlintptrfromotherthread );
MessageBox. Show (controlcreatedfromotherthread. Name );
}

Private void createcontrolinstance ()
{
Control newcontrolinstance = new control ();
Newcontrolinstance. Name = "Hello, Leland ";
Controlintptrfromotherthread = newcontrolinstance. Handle;
}

In this example, a control and handle are created in a non-main thread, and the handle is saved in a global variable. Back to the main thread, you can still obtain the Control Based on handle.

However, something strange happened. In the preceding example, "Hello, Leland" is given to the name attribute of the control. In the main thread dialog box, "Hello, Leland", this is correct. I tried to give "Hello, Leland" to the text attribute. However, an empty string is thrown ....

This example only shows that different threads can share a heap .. Let's not talk about the deadlock example. Haha.

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.