The correct way to use SyncLock (in general)

This is a continuation of the previous question about locking two List (Of T) objects. The answer there was helpful, but left me with a different question.

Suppose I have a function like this:

Public Function ListWork() As Integer List1.Clear() ..Some other work which does not modify List1.. List1.AddRange(SomeArray) ..Some more work that does not involve List1.. Return List1.Count End Function 

which is in the class that declares List1. In a multi-threaded environment, I now understand that I need to have a private lock object for List1 and lock List1 whenever it changes or is listed. My question is should I do this:

 Private List1Lock As New Object Public Function ListWork() As Integer SyncLock List1Lock List1.Clear() End SyncLock ..Some other work which does not modify List1.. SyncLock List1Lock List1.AddRange(SomeArray) End SyncLock ..Some more work that does not involve List1.. SyncLock List1Lock Dim list1Count As Integer = List1.Count End SyncLock Return list1Count End Function 

or that:

 Private List1Lock As New Object Public Function ListWork() As Integer SyncLock List1Lock List1.Clear() ..Some other work which does not modify List1.. List1.AddRange(SomeArray) ..Some more work that does not involve List1.. Dim list1Count As Integer = List1.Count End SyncLock Return list1Count End Function 

I assume the first example is optimal?

+6
optimization multithreading locking
source share
2 answers

From the examples it is difficult to determine which one is correct, if any. A few recommendations / observations, although this may help you answer your question or know what to provide additional information:

First, do I need to sync? Would it make sense for each thread to have an instance of this class? If each instance is local to the stream and is only modified and used in this stream, you do not need to block.

If the purpose of this class and the use of threads is to process a larger set of data in parallel, it may make more sense for the main thread to split the task in some logical way, and then wait until the work flows complete.In this case, instead of managing the threads, consider ThreadPool yourself and wait for the handles. Most of the dirty work is done for you then.

About synchronization / locking in general: if your operation was interrupted between steps, will the data be consistent / valid?

In your example, let's say you have two threads. The first is in the area between .AddRange() and .Count when the second thread enters the function and gets a lock in the list.

Thread 1 works a little more and hits the lock protecting the .Count method and goes into sleep mode. Tempo 2, meanwhile, clears the list and then releases its lock, waking Thread 1 up, which then gets the lock.

In this case, Thread 1 will return 0 from this function when the work was performed by thread 1 to create a list. And then the length of the list will not really be 0, since stream 2 came and populated the list.

In this case, locks around individual list operations interrupt the program, so it makes sense to have one lock surrounding between Clear and the call to Count .

In short, multithreading is a good way to introduce a whole class of subtle bugs related to race conditions that often lead to Heisenbugs .

It is often useful to avoid threads when you can. If you cannot, try organizing your workload in ways that require minimal synchronization (for example, by providing a stream with a dataset at the beginning and then waiting for it to complete, for example, a related example of a thread pool). If you cannot do this, proceed carefully and always ask yourself: "What happens if two threads work in this area."

Hope this helps you in future adventures in multi-threaded code.

+9
source share

"It depends". Two examples have different semantics.

In the last example, the entire set of operations is atomic with respect to locking. Although in the first example, access to the list is protected by locking, but the entire set of operations cannot be (correctly) considered atomic (relative to locking).

Imagine what could / would happen in terms if the rotation of operations / threads, if ListWork was called by the same object by different threads.

Happy coding.

+6
source share

All Articles