Recommendation 22: Ensure thread safety for collections
Collection thread security is when elements are added or removed on multiple threads, and the line Cheng must be kept in sync.
The following code simulates one thread during the iteration, and the other thread deletes the element.
classProgram {Staticlist<person> list =NewList<person>() { NewPerson () {Name ="Rose", age = + }, NewPerson () {Name ="Steve", age = $ }, NewPerson () {Name ="Jessica", age = - }, }; StaticAutoResetEvent AutoSet =NewAutoResetEvent (false); Static voidMain (string[] args) {Thread T1=NewThread (() = { //Be sure to wait for T2 to start before running the following codeAutoset.waitone (); foreach(varIteminchlist) {Console.WriteLine ("T1:"+item. Name); Thread.Sleep ( +); } }); T1. Start (); Thread T2=NewThread (() = { //notifies T1 that code can be executedAutoset.set (); //sleeps 1 seconds to ensure that the delete operation is in the T1 iterationThread.Sleep ( +); List. RemoveAt (2); }); T2. Start (); } } classPerson { Public stringName {Get;Set; } Public intAge {Get;Set; } }
The above code will throw InvalidOperationException: "The collection has been modified and the enumeration may not be executed." ”
Before a generic collection appears, a non-generic collection typically provides a SyncRoot property that is guaranteed to be thread-safe for a non-generic collection, which can be implemented by locking the property. If the above collection is replaced with ArrayList, ensure that its thread safety should be added with lock when iterating and deleting, the code is as follows:
StaticArrayList list =NewArrayList () {NewPerson () {Name ="Rose", age = + }, NewPerson () {Name ="Steve", age = $ }, NewPerson () {Name ="Jessica", age = - }, }; StaticAutoResetEvent AutoSet =NewAutoResetEvent (false); Static voidMain (string[] args) {Thread T1=NewThread (() = { //Be sure to wait for T2 to start before running the following codeAutoset.waitone (); Lock(list. SyncRoot) {foreach(Person iteminchlist) {Console.WriteLine ("T1:"+item. Name); Thread.Sleep ( +); } } }); T1. Start (); Thread T2=NewThread (() = { //notifies T1 that code can be executedAutoset.set (); //sleeps 1 seconds to ensure that the delete operation is in the T1 iterationThread.Sleep ( +); Lock(list. SyncRoot) {list. RemoveAt (2); Console.WriteLine ("Delete succeeded"); } }); T2. Start (); }
The above code does not throw an exception because the lock ensures that only one thread can manipulate the collection element at the same time by means of a mutually exclusive mechanism. We then find that the generic collection does not have such a property and must create a lock object on its own to complete the synchronization task. You can lock by a new static object, with the following code:
Staticlist<person> list =NewList<person>() { NewPerson () {Name ="Rose", age = + }, NewPerson () {Name ="Steve", age = $ }, NewPerson () {Name ="Jessica", age = - }, }; StaticAutoResetEvent AutoSet =NewAutoResetEvent (false); Static ObjectSycobj =New Object(); Static voidMain (string[] args) { //Object sycobj = new Object ();Thread T1 =NewThread (() = { //Be sure to wait for T2 to start before running the following codeAutoset.waitone (); Lock(sycobj) {foreach(Person iteminchlist) {Console.WriteLine ("T1:"+item. Name); Thread.Sleep ( +); } } }); T1. Start (); Thread T2=NewThread (() = { //notifies T1 that code can be executedAutoset.set (); //sleeps 1 seconds to ensure that the delete operation is in the T1 iterationThread.Sleep ( +); Lock(sycobj) {list. RemoveAt (2); Console.WriteLine ("Delete succeeded"); } }); T2. Start (); }
Turn from: 157 recommendations for writing high-quality code to improve C # programs Minjia
157 recommendations for writing high-quality code to improve C # programs--recommendation 22: Ensure thread safety for collections