C # multi-threaded programming Step 2-thread synchronization and thread security,
The previous blog learned how to use multithreading. In fact, General multithreading is really simple, but a safe and efficient multithreading is not that simple. Therefore, improper use of multithreading may affect the program performance.
The following is an example:
Class Program {static int num = 1; static void Main (string [] args) {Stopwatch stopWatch = new Stopwatch (); // start the timer stopWatch. start (); ThreadStart threadStart = new ThreadStart (Run); for (int I = 0; I <5; I ++) {Thread thread = new Thread (threadStart); thread. start ();} num ++; Console. writeLine ("num is:" + num); Console. writeLine ("Main thread ID is:" + Thread. currentThread. managedThreadId. toString (); // stop the timer stopWatch. stop (); // the execution time of the output, in milliseconds. writeLine ("The execution time is" + stopWatch. elapsedMilliseconds + "milliseconds. "); Console. readKey ();} public static void Run () {num ++; Console. writeLine ("num is:" + num); Console. writeLine ("Child thread ID is:" + Thread. currentThread. managedThreadId. toString ());}}
Execution result:
From the above, we can see that the value of the variable num is not continuously increasing, and the output is not sequential, and the value of each output is different because the asynchronous thread accesses a member at the same time, therefore, such multithreading is uncontrollable for us. The preceding example is non-thread-safe. To ensure thread security, thread synchronization is required. There are many ways to synchronize threads. For example, the Join () method previously used can also synchronize threads. Next let's try:
Class Program {static int num = 1; static void Main (string [] args) {Stopwatch stopWatch = new Stopwatch (); // start the timer stopWatch. start (); ThreadStart threadStart = new ThreadStart (Run); for (int I = 0; I <5; I ++) {Thread thread = new Thread (threadStart); thread. start (); thread. join ();} num ++; Console. writeLine ("num is:" + num); Console. writeLine ("Main thread ID is:" + Thread. currentThread. managedThreadId. toString (); // stop the timer stopWatch. stop (); // the execution time of the output, in milliseconds. writeLine ("The execution time is" + stopWatch. elapsedMilliseconds + "milliseconds. "); Console. readKey ();} public static void Run () {num ++; Console. writeLine ("num is:" + num); Console. writeLine ("Child thread ID is:" + Thread. currentThread. managedThreadId. toString ());}}
Execution result:
In this way, simple synchronization is implemented. Compared with the above Code, only a line of code (thread. join ();), previously mentioned the Join () method is used to block the current thread until the previous thread execution is complete. However, although synchronization is implemented in this way, the execution of the main thread is blocked, which is no different from that of a single thread. In this case, we can learn other methods.
There is also a lock mechanism for implementing thread synchronization. The following is the simplest lock mechanism, that is, using lock. As follows:
Class Program {private object locker = new object (); int num = 1; static void Main (string [] args) {Program program = new Program (); stopwatch stopWatch = new Stopwatch (); // start the timer stopWatch. start (); ThreadStart threadStart = new ThreadStart (program. run); for (int I = 0; I <5; I ++) {Thread thread = new Thread (threadStart); thread. start ();} program. num ++; Console. writeLine ("num is:" + program. num); Console. writeLine ("Main thread ID is:" + Thread. currentThread. managedThreadId. toString (); // stop the timer stopWatch. stop (); // the execution time of the output, in milliseconds. writeLine ("The execution time is" + stopWatch. elapsedMilliseconds + "milliseconds. "); Console. readKey () ;}public void Run () {lock (locker) {num ++; Console. writeLine ("num is:" + num); Console. writeLine ("Child thread ID is:" + Thread. currentThread. managedThreadId. toString ());}}}
Execution result:
Lock is a simple and easy-to-use thread synchronization method, which is implemented by obtaining mutex locks for a given object. We can see that this method does not block the main thread, and the value of the member variable is continuously increasing, which indicates thread safety. The lock mechanism means that only one thread can lock the synchronization object at the same time (here it is locker), and any other competing threads will be blocked until the lock is released.
The lock parameter must be an object of the reference type, not a basic type, such as bool or int, which cannot be synchronized at all because the lock parameter must be an object. If int Is input, the boxing operation is bound to occur, so that each lock will be a new and different object. It is best to avoid using public or program-controlled object instances, because this may lead to deadlocks. Never lock a string.
We will go here for the time being, and learn other methods later to continue the update.