In multithreading, to maintain data consistency, you must lock the data or function that accesses the data. This is common in the database, but most of the programs are single-threaded, therefore, there is no need for locking, but in multithreading, to maintain data synchronization, We must lock it. Fortunately, the Framework already provides us with three locking mechanisms, they are the Monitor class, Lock keyword, and Mutex class.
The usage of the Lock keyword is relatively simple. The usage of the Monitor class is similar to that of the Lock class. Both of them lock the data or lock the called function. Mutex is mostly used to lock synchronous calls between multiple threads. In short, Monitor and Lock are mostly used to Lock the called end, while Mutex is used to Lock the called end. For example, the following program: because such programs are within milliseconds, running the following program may have different results on different machines, running on the same machine at different times has different results. My testing environment is vs2005, windowsXp, CPU3.0, and 1G monery. There are two threads thread1, thread2, and a TestFunc function in the program. TestFunc prints the thread name for calling it and the call time (mm-level ), the two threads call the function TestFunc with 30mm and 100mm respectively. The execution time of TestFunc is 50mm. The program is as follows: using System; using System. collections. generic; using System. text; using System. threading; namespace MonitorLockMutex {class Program {# region variable Thread thread1 = null; Thread thread2 = null; Mutex mutex = null; # endregion static void Main (string [] args) {Program p = new Program (); p. runThread (); Console. readLine () ;}public Program () {mutex = new Mutex (); thread1 = new Thread (new ThreadStart (thread1Func )); thread2 = new Thread (new ThreadStart (thread2Func);} public void RunThread () {thread1.Start (); thread2.Start ();} private void thread1Func () {for (int count = 0; count <10; count ++) {TestFunc ("Thread1 have run" + count. toString () + "times"); Thread. sleep (30) ;}} private void thread2Func () {for (int count = 0; count <10; count ++) {TestFunc ("Thread2 have run" + count. toString () + "times"); Thread. sleep (100) ;}} private void TestFunc (string str) {Console. writeLine ("{0} {1}", str, System. dateTime. now. millisecond. toString (); Thread. sleep (50:
We can see that if no lock is applied, the two threads read the TestFunc function according to their respective time interval + TestFunc execution time (50mm. Because the thread needs to allocate memory at the beginning, 0th calls are inaccurate, from 1st ~ The execution interval of thread1 is about 80mm, and the execution interval of thread2 is about 150mm. Modify TestFunc as follows: private void TestFunc (string str) {lock (this) {Console. writeLine ("{0} {1}", str, System. dateTime. now. millisecond. toString (); Thread. sleep (50) ;}} or use Monitor, as shown in the following code: private void TestFunc (string str) {Monitor. enter (this); Console. writeLine ("{0} {1}", str, System. dateTime. now. millisecond. toString (); Thread. sleep (50); Monitor. exit (this);} both Enter and Exit are static methods in Monitor. The result of running Lock is as follows: Let's analyze the result, which also starts from 1st times. The call interval between the same threads is the thread execution time + TestFunc call time. The call interval between different threads is the TestFunc call time. For example, the interval between two consecutive calls of thread1 is about 30 + 50 = 80; the interval between two consecutive calls of thread2 is about 100 + 50 = 150. The interval between calling thread1 and thread2 is 50mm. Because TestFunc is locked, after a thread calls TestFunc, when other threads call TestFunc at the same time, the later threads will be queued to the waiting queue for waiting, until the thread with access permission releases the resource. This is the feature of locking the called function, that is, only one thread can call each time, the number of calls with a higher thread priority is more, and the number of calls with a lower thread priority is less. This is the so-called strong proportion. Next let's take a look at the usage of the Mutex class, and the difference with Monitor and Lock. Modify the Code as follows: private void thread1Func () {for (int count = 0; count <10; count ++) {mutex. waitOne (); TestFunc ("Thread1 have run" + count. toString () + "times"); mutex. releaseMutex ();}}
Private void thread2Func () {for (int count = 0; count <10; count ++) {mutex. waitOne (); TestFunc ("Thread2 have run" + count. toString () + "times"); mutex. releaseMutex ();}}