多线程和关键部分使用 - C ++

时间:2010-12-13 22:18:43

标签: c++ multithreading visual-studio-2008 winapi critical-section

我对在多线程应用程序中正确使用关键部分感到困惑。在我的应用程序中,有几个在线程之间共享的对象(一些循环缓冲区和一个串行端口对象)。是否应将这些对象的访问权限置于关键部分内,或仅在特定时间进行?我怀疑只是在某些时候,因为当我试图用EnterCriticalSection / LeaveCriticalSection包裹每次使用时,我遇到了似乎是死锁的情况。您可能有任何见解将不胜感激。感谢。

2 个答案:

答案 0 :(得分:6)

如果您跨线程共享资源,并且其他一些线程在其他线程写入时读取,那么它必须始终受到保护。

如果不了解更多关于代码的内容,很难提供更多建议,但这里有一些要记住的一般要点。

1)关键部分保护资源,而不是进程

2)在所有线程中以相同的顺序输入/离开关键部分。如果线程A进入Foo,然后输入Bar,则线程B必须以相同的顺序输入Foo和Bar。如果不这样做,你可以创建一个种族。

3)必须以相反的顺序进入和离开。例如,由于您输入了Foo然后进入了Bar,您必须在离开Foo之前​​离开Bar。如果你不这样做,你可能会造成死锁。

4)合理地在最短的时间内保持锁定。如果你在开始使用Bar之前已经完成了Foo,那么在抓住Bar之前释放Foo。但是你仍然必须从上面牢记订购规则。在同时使用Foo和Bar的每个线程中,您必须以相同的顺序获取和释放:

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

5)如果你只读了99.9%的时间并写了0.1%的时间,不要试图聪明。即使你只是在阅读,你仍然必须进入暴击秒。这是因为当你在阅读过程中时,你不希望写入开始。

6)保持关键部分的细化。每个关键部分应该保护一个资源,而不是多个资源。如果你使关键部分太“大”,你可以序列化你的应用程序或创建一组非常神秘的死锁或种族。

答案 1 :(得分:2)

在支持RAII的关键部分周围使用C ++包装器:

{
    CriticalSectionLock lock ( mutex_ );

    Do stuff...
}

锁的构造函数获取互斥锁,即使抛出异常,析构函数也会释放互斥锁。

尽量不要一次获得超过一个锁,并尽量避免在持有锁时调用类外的函数;这有助于避免在不同的地方获得锁定,因此您可以减少死锁的可能性。

如果您必须同时获得多个锁,请按地址对锁进行排序并按顺序获取。这样,多个进程在没有协调的情况下以相同的顺序获得相同的锁。

使用IO端口,考虑是否需要在输入的同时锁定输出 - 通常情况下,某些东西会尝试写入,然后期望读取,反之亦然。如果你有两个锁,那么你可以在一个线程写入然后读取时获得死锁,然后另一个读取然后写入。通常有一个执行IO和请求队列的线程解决了这个问题,但这比仅使用锁包装调用要复杂一点,而且没有更多细节我不推荐它。