顯示具有 Notes of C# 標籤的文章。 顯示所有文章
顯示具有 Notes of C# 標籤的文章。 顯示所有文章

2009年2月12日 星期四

Delegate and Thread-Safe

中文版按這裡

In two previous articles, "POP3 == RFC 1939" and "What the hell is "=?big5?B? "?" (They were written in Chinese and I'll translate those into English afterward.), which discuss about reading messages from a POP3 server and decoding Chinese characters from header of messages. It is a problem to interrupting the message reading for the program mentioned above, due to single thread execution. It means only one thread is used for executing the program; And it is not able to monitor requests from user, such as a "Cancel" button has been clicked by user, while this single thread is busy for getting messages from POP3 server. To quit the program seems the only way to interrupt message reading during a long waiting time cause by a large amount of messages on server.  However, we can let the program check requests from user after pausing message reading, and then does the exact same things in next loops till the end/stop of reading. It'll cost a longer reading period of time and make the program more complicated. Multithreading is another alternative solution and it is an easier one for programming, frankly. For example, use the original tread to monitor requests form user and an additional one for messages reading. Multithreading might help us out of this; nevertheless, it causes new problems! That is, threads compete against each others for resources; it makes executions unpredictable! We don't want to see these happening. Let's read related information on MSDN: "Access to Windows Forms controls is not inherently thread safe. If you have two or more threads manipulating the state of a control, it is possible to force the control into an inconsistent state. Other thread-related bugs are possible, such as race conditions and deadlocks. It is important to make sure that access to your controls is performed in a thread-safe way." It has to be tested which thread the control belongs to before manipulating it, in order to keep away from those situations of race conditions and deadlocks. A thread is allowed to manipulate a control, if it was created by this thread. Otherwise, this thread has to "ask" help from the one that created that control; This is so-called "Thread-Safe"You might want to know what on earth the "Thread-Safe" is, please refers to the article "Thread-Safe的理解與分析" of "蕭沖的書房", you might be able to get a rough idea about it! There is copious example on MSDN for explanation about thread-safe, following are excerpt from the example. It's main concept is that checking the value of property InvokeRequired to decide whether the caller must call an Invoke method when making method calls to the control because the caller is on a different thread than the one the control was created on. This means that InvokeRequired can return false if Invoke is not required (the call occurs on the same thread). And "Delegate" is a helpful tool in the case of Invoke is required. Check it out following: namespace CrossThreadDemo { public class Form1 : Form { // This delegate enables asynchronous calls for setting // the text property on a TextBox control. // (And it will be applied for making the method "Invoke" call.) delegate void SetTextCallback(string text); ... Following is the major part of thread-safe for setting a property of control. // This method demonstrates a pattern for making thread-safe // calls on a Windows Forms control. // // If the calling thread is different from the thread that // created the TextBox control, this method creates a // SetTextCallback and calls itself asynchronously using the // Invoke method. // // If the calling thread is the same as the thread that created // the TextBox control, the Text property is set directly. private void SetText(string text) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. // (the Delegate "SetTextCallback" can be find here.) if (this.textBox1.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); } else { this.textBox1.Text = text; } }

2009年2月8日 星期日

The Delegate of C#

中文版

What the hell is Delegate? Let's read about it on MSDN: "A delegate is a type that defines a method signature, and can be associated with any method with a compatible signature. You can invoke (or call) the method through the delegate. Delegates are used to pass methods as arguments to other methods. Event handlers are nothing more than methods that are invoked through delegates." Hum~, it's a little bit hard to get it straight! Let's take another shot on MSDN: "A delegate is a reference type that can be used to encapsulate a named or an anonymous method. Delegates are similar to function pointers in C++; however, delegates are type-safe and secure." All right, forget about the definition of it, let's try the example codes provided on MSDN. We might get a rough idea of it: // Declare delegate -- defines required signature: // Any methods that instantiated with it has to match it's signature: // A parameter of double is required and returns a double. delegate double MathAction(double num); class DelegateTest { // Regular method that matches signature: static double Double(double input) { return input * 2; } static void Main() { // Instantiate delegate with named method: // "ma" in the next line is "similar to function pointers in C++" , expressed  previously. MathAction ma = Double; // Invoke delegate ma: // The express "ma(4.5)" is identical to "Double(4.5)" double multByTwo = ma(4.5); Console.WriteLine(multByTwo); // Instantiate delegate with anonymous method: // The concept of anonymous method is similar to the previous one. MathAction ma2 = delegate(double input) { return input * input; }; double square = ma2(5); Console.WriteLine(square); // Instantiate delegate with lambda expression MathAction ma3 = s => s * s * s; double cube = ma3(4.375); Console.WriteLine(cube); } } The example code above is executable directly! All you need is creating a Console Application of C#, and then paste the example to the file Program.cs; Be aware of the first line "using System;" that was generated automatically while new project was creating. It is necessary for running the example correctly.