Use synchronizationcontext to implement two different programming models for Synchronous access to thread-safe UI

Source: Internet
Author: User

Preface:

When multiple threads access a thread-safe resource, such as the UI, there must be some kind of mechanism to ensure that these threads operate aling. If resources requiring thread-safe are simultaneously accessed by other threads without any measures, the following similar invalidoperationexception will be thrown.

Cross - Thread operation not valid: Control ' M_counterlabel ' Accessed from a thread other than the thread it was created on.

Excpetion screenshot is as follows:

 

Programming Model 1:

In the following sample, myform provides a propertity called Allow client access to obtain the mysynchronizationcontext of the UI. Mysynchronizationcontext is initialized by obtaining the context of the current thread in the constructor of myform. Myform also provides counter property to update the Windows Forms label of the server. Of course. counter can only be accessed by the current thread of the form.

Source code:

Service UI

Using System;
Using System. Collections. Generic;
Using System. componentmodel;
Using System. Data;
Using System. drawing;
Using System. LINQ;
Using System. text;
Using System. Windows. forms;

namespace uisynchronizationcontext_service
{< br> Public partial class myform: form
{< br> private system. windows. forms. label m_counterlabel;
system. threading. synchronizationcontext m_synchronizationcontext;

Public myform ()
{< br> initializecomponent ();
m_synchronizationcontext = system. threading. synchronizationcontext. current;
system. diagnostics. debug. assert (m_synchronizationcontext ! = null );
}

PublicSystem. Threading. synchronizationcontext mysynchronizationcontext
{
Get
{
ReturnM_synchronizationcontext;
}
}

Public   Int Counter
{
Get { Return Convert. toint32 (m_counterlabel.text );}
Set {M_counterlabel.text = Value. tostring ();}
}
Private   Void Myform_load ( Object Sender, eventargs E)
{

}
}
}

Service Contract and implementation

Using System;
Using System. Collections. Generic;
Using System. LINQ;
Using System. text;
Using System. servicemodel;

NamespaceUisynchronizationcontext_service
{
[Servicecontract]
Public InterfaceIformmanager
{
[Operationcontract (isoneway= True)]
VoidIncrementlabel ();
}

Class Mycontract: iformmanager
{
Public   Void Incrementlabel ()
{
Myform form = System. Windows. Forms. application. openforms [ 0 ] As Myform;
System. Diagnostics. Debug. Assert (Form ! =   Null );
Sendorpostcallback callback =   Delegate
{
Form. Counter ++ ;
};

Form. mysynchronizationcontext. Send (callback,Null);

}
}

Static   Class Program
{
///   <Summary>
/// The main entry point for the application.
///   </Summary>
[Stathread]
Static   Void Main ()
{
Application. enablevisualstyles ();
Application. setcompatibletextrenderingdefault ( False );

Servicehost host= NewServicehost (Typeof(Mycontract ));
Host. open ();

Application. Run (NewMyform ());
Host. Close ();
}
}
}

Running result:

Service updated UI by multiple threads

#1 client CILS for service to update service's UI

 

#2 client CILS for service to update service's UI

Disadvantages:

The defiency of the programming model is that the service and UI form are too coupled. Obviously, this is a bad design model. It is inconvenient to update multiple controls in form. The ideal design method is to use the service and UI form decouple, which are independent of each other.

Programming Model 2:

So how to implement this programming model? We can customize thread-safe control. Encapsulate the thread-safe operations required for synchronization context with Windows form in these so-called safe controls to decouple them from the service.

For exampleCodeSlight modification:

1. we add a m_mytextbox reference to form, but in fact this m_mytextbox is a reference of mytexbbox, which is a custom derived from system. windows. forms. safe textbox class of text. We override some of its methods or propertity so that it runs under thread-safe:

The following is the definition of the custom textbox mytextbox.

Using System;
Using System. Collections. Generic;
Using System. LINQ;
Using System. text;
Using System. Windows. forms;
Using System. Threading;

NamespaceUisynchronizationcontext_service
{
ClassSafetextbox: textbox
{
Synchronizationcontext m_synchronizationcontext=Synchronizationcontext. Current;

Public   Override   String Text
{
Set
{
Sendorpostcallback settext =   Delegate ( Object Text)
{
Base . Text = Text As   String ;
};
M_synchronizationcontext.send (settext, value );
}
Get
{
String Text = String. empty;
Sendorpostcallback gettext =   Delegate
{
Text =   Base . Text;
};
M_synchronizationcontext.send (gettext, Null );
Return Text;
}
}


}
}

Assume that an operation is added to servicecontract:

[Operationcontract (isoneway = true)]

Void updatetextbox (string textboxvalue );

Used to Modify text in textbox.

Its implementation Implementation is as follows:

Class Mycontract: iformmanager
{
Public   Void Incrementlabel ()
{
Myform form = System. Windows. Forms. application. openforms [ 0 ] As Myform;
System. Diagnostics. Debug. Assert (Form ! =   Null );
Sendorpostcallback callback =   Delegate
{
Form. Counter ++ ;
};

Form. mysynchronizationcontext. Send (callback,Null);

}

Public   Void Updatetextbox ( String Textboxvalue)
{
Myform form = System. Windows. Forms. application. openforms [ 0 ] As Myform;
Form. textboxvalue=Textboxvalue;
}
}

 

There is only one very simple statement! All the synchronization context operations on the control are encapsulated in its safe control: So cool.

Of course, the client code is also modified as follows:

Using System;
Using System. Collections. Generic;
Using System. LINQ;
Using System. text;

Namespace Uisynchronizationcontext_client
{
Class Program
{
Static   Void Main ( String [] ARGs)
{
Formmanagerclient proxy =   New Formmanagerclient ();
Console. writeline ( " Press any key to continue processing " );
Console. Readline ();
Proxy. incrementlabel ();
For ( Int I =   0 ; I <   10 ; I ++ )
{
Proxy. updatetextbox ( " Value set from #1 client is "   + I. tostring ());
System. Threading. thread. Sleep ( 2000 );
}
Console. writeline ( " Updated service's UI " );
Console. Readline ();
}
}
}

In order to see how the safe control of the service authenticates these update control requests, this operation is specially given for 10 consecutive times.

How can multiple different clients call the service continuously? We can see that the text in the textbox of the service is continuously updated by different client threads.

Running result:

The service UI running result is as follows:

for source code regarding to this article, pls press here to download

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.