【问题标题】:C++ Is Mutex the only way to lock shared resourcesC++ 是 Mutex 锁定共享资源的唯一方法
【发布时间】:2014-10-01 03:44:07
【问题描述】:
除了互斥锁,你还能用什么来锁定 C++?处理器级别有什么可以使用的吗?
【问题讨论】:
标签:
c++
multithreading
visual-c++
c++11
【解决方案1】:
您可以使用比较和交换,类似于:
std::atomic_bool locked = false;
bool f = false;
... // spawn threads n' stuff
do {
bool got_lock = atomic_compare_exchange_weak(locked, &f, true);
if (got_lock) {
... // do stuff
locked = false;
}
}
while(!got_lock)
我在概念上将变量命名为locked 和got_lock,但这里没有真正的锁定。 atomic_compare_exchange_weak 函数利用特殊的汇编指令来实现原子性。
要了解它是如何工作的:它进入 do while 循环并立即尝试 CAS。 CAS 将locked 的值与f 中包含的值进行比较,结果为假。当且仅当它们比较相等时,它将locked 设置为第三个参数(true)并返回true。否则,这意味着另一个线程已经将locked设置为true,因此它返回false并且不会更改locked的值。我们可以看到,如果一个线程获得了锁,它会进入 if,做一些事情,然后释放锁。如果它没有获得锁,它不会通过 if,但它会被 while 循环弹回。它在这个非常快的 while 循环中继续,直到 CAS 调用成功。
所以,在我写下“做事”评论的地方,您可以保证一次只能有一个线程。
【解决方案2】:
如果您在操作系统下开发,那么您也可以使用信号量。与互斥锁相比,信号量可以用某个数字作为计数器进行初始化。您初始化信号量的值允许任何调用者获取资源或执行关键代码部分,直到值(信号量)大于零。当它倒数为零时,任何新的调用者都将等待释放/释放信号量。并且二进制信号量本身就是互斥体。
【解决方案3】:
操作系统原语与锁相比有一个关键优势,即使用操作系统原语会将您的线程放入内核中的等待队列中。当一个互斥锁被释放时,你的线程可以被操作系统自动唤醒并启动。如果您使用比较/交换类型检查,您有责任编写自旋锁并适当地休眠(否则当您没有锁时,您将使用 100% 的处理器(或内核)等待它释放)。
Mutex 擅长跨进程同步(需要操作系统)。 Semaphore 非常相似,只是它允许并发访问临界区(例如,允许 4 个线程仅从工作队列运行以优化多核处理器上的工作)。
如果您只在同一进程中同步线程,您还可以使用“CRITICAL_SECTION”MSDN LINK。这会更快,因为您不需要系统调用来实现锁定。