简体   繁体   中英

Correct pattern for multi-thread synchronization? (C#)

I have two threads referencing the same variable -- the UI thread and a timer thread. As such, I have wrapped access to it in lock statements in both threads. The timer thread's access has priority -- if it's using the variable and the UI thread also wants access, I want the UI thread's operation to complete, but only after the timer thread's operation completes.

However, the timer thread may delegate back to the UI thread, so the UI thread needs to be free to handle that. To accommodate that, I have the UI thread launching a third thread to handle its operation so that it (that third thread) can wait for the timer operation to complete and the UI thread can be available. The locking happens in that third thread.

What is the correct pattern I should be using for this sort of synchronization?

The general recommendation is that whatever is happening in critical sections should be as simple as possible. In particular you should avoid nested locks. Nested locks potentially are the source of deadlocks.

As applied to what you are doing in your 'timer' thread you probably should separate the critical sections from processing. IOW in the timer thread just retrieve the data from the common variable(s) and then do the rest of the processing including interactions with UI thread outside the lock.

Adding a third thread to the mix will not make your life any easier

The rule of thumb is to use the lightest lock for the shortest time possible.

There is quite a good article here: http://www.moserware.com/2008/09/how-do-locks-lock.html

A general rule to follow is that you minimize the amount of time that you hold a lock, and you don't call code you don't own and control (such as an event, a virtual method, or a UI thread) while holding a lock.

So the timer should not call back into the UI while holding the lock. If it needs transactional access to the data under the lock (read, call UI, write), then it should probably be designed to roll back and/or retry.

Like mfeingold said, avoid it where possible. Where you cannot avoid it take care of taking the locks in both threads in the same order! I mean, if you have three locks A, B and C, if you have following lock patterns

  • Thread 1: A->B->C
  • Thread 2: A->C->B

then a deadlock is possible...

Nesting locks usually costs performance as you have to lock the outer locks even if you would sometimes not need to to ensure correct behavior in the case where the method is called from another thread.

Why are you doing this? It sounds complicated and error prone.

What is the timer thread delegating to the UI thread for?

It may be the case that it's necessary, but my immediate reaction is that you probably need to take a step back and consider whether your design is unnecessarily forcing you into complex synchronization issues.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM