Tho*_*mas 11 c++ multithreading gcc pthreads thread-safety
我希望在我的项目中尽可能减少同步并编写无锁代码.当绝对必要时,我喜欢用pthread和win32互斥锁替换原子操作中构建的轻量级自旋锁.我的理解是这些是下面的系统调用并且可能导致上下文切换(对于非常快速的关键部分而言,这可能是不必要的,其中简单地旋转几次将是更可取的).
我所指的原子操作在这里有很好的记录:http://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Atomic-Builtins.html
这是一个例子来说明我在说什么.想象一下可能有多个读者和作者的RB树.RBTree :: exists()是只读且线程安全的,RBTree :: insert()需要单个编写器(而不是读者)的独占访问才是安全的.一些代码:
class IntSetTest
{
private:
unsigned short lock;
RBTree<int>* myset;
public:
// ...
void add_number(int n)
{
// Aquire once locked==false (atomic)
while (__sync_bool_compare_and_swap(&lock, 0, 0xffff) == false);
// Perform a thread-unsafe operation on the set
myset->insert(n);
// Unlock (atomic)
__sync_bool_compare_and_swap(&lock, 0xffff, 0);
}
bool check_number(int n)
{
// Increment once the lock is below 0xffff
u16 savedlock = lock;
while (savedlock == 0xffff || __sync_bool_compare_and_swap(&lock, savedlock, savedlock+1) == false)
savedlock = lock;
// Perform read-only operation
bool exists = tree->exists(n);
// Decrement
savedlock = lock;
while (__sync_bool_compare_and_swap(&lock, savedlock, savedlock-1) == false)
savedlock = lock;
return exists;
}
};
Run Code Online (Sandbox Code Playgroud)
(我们假设它不必是例外安全的)
这段代码确实是线程安全的吗?这个想法有利有弊吗?有什么建议?如果线程不是真正并发的话,使用像这样的自旋锁是个坏主意吗?
提前致谢.;)
你需要一个volatile
限定符lock
,我也会把它变成一个sig_atomic_t
。如果没有volatile
限定符,此代码:
u16 savedlock = lock;
while (savedlock == 0xffff || __sync_bool_compare_and_swap(&lock, savedlock, savedlock+1) == false)
savedlock = lock;
Run Code Online (Sandbox Code Playgroud)
在 while 循环体中lock
更新时可能不会重新读取。考虑0xffff 的savedlock
情况。lock
然后,savedlock
在检查循环条件之前将为 0xffff,因此while
条件将在调用之前短路__sync_bool_compare_and_swap
。由于__sync_bool_compare_and_swap
没有被调用,编译器不会遇到内存障碍,因此它可能合理地假设 的值lock
在您下面没有改变,并避免在savedlock
.
回复: ,这里sig_atomic_t
有一个不错的讨论。适用于信号处理程序的相同注意事项也适用于线程。
通过这些更改,我猜您的代码将是线程安全的。不过,我仍然建议使用互斥体,因为您确实不知道在一般情况下您的 RB 树插入需要多长时间(根据我之前在该问题下的评论)。