Multithreading and Critical Sections Use - C++

Jim Fell picture Jim Fell · Dec 13, 2010 · Viewed 12.1k times · Source

I'm a little confused as to the proper use of critical sections in multithreaded applications. In my application there are several objects (some circular buffers and a serial port object) that are shared among threads. Should access of these objects always be placed within critical sections, or only at certain times? I suspect only at certain times because when I attempted to wrap each use with an EnterCriticalSection / LeaveCriticalSection I ran into what seemed to be a deadlock condition. Any insight you may have would be appreciated. Thanks.

Answer

John Dibling picture John Dibling · Dec 13, 2010

If you share a resource across threads, and some of those threads read while others write, then it must be protected always.

It's hard to give any more advice without knowing more about your code, but here are some general points to keep in mind.

1) Critical sections protect resources, not processes.

2) Enter/leave critical sections in the same order across all threads. If thread A enters Foo, then enters Bar, then thread B must enter Foo and Bar in the same order. If you don't, you could create a race.

3) Entering and leaving must be done in opposite order. Example, since you entered Foo then entered Bar, you must leave Bar before leaving Foo. If you don't do this, you could create a deadlock.

4) Keep locks for the shortest time period reasonably possible. If you're done with Foo before you start using Bar, release Foo before grabbing Bar. But you still have to keep the ordering rules in mind from above. In every thread that uses both Foo and Bar, you must acquire and release in the same order:

  Enter Foo
  Use Foo
  Leave Foo
  Enter Bar
  Use Bar
  Leave Bar

5) If you only read 99.9% of the time and write 0.1% of the time, don't try to be clever. You still have to enter the crit sec even when you're only reading. This is because you don't want a write to start when your'e in the middle of a read.

6) Keep the critical sections granular. Each critical section should protect one resource, not multiple resources. If you make the critical sections too "big", you could serialize your application or create a very mysterious set of deadlocks or races.