首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >是否可以使用__sync_local_test_and_set/xchg实现互斥锁?

是否可以使用__sync_local_test_and_set/xchg实现互斥锁?
EN

Stack Overflow用户
提问于 2022-10-14 12:09:45
回答 1查看 28关注 0票数 0

大多数__sync_local_test_and_set的搜索结果都提到它可以用来实现自旋锁而不是互斥锁。文章多线程编程:锁定效率还读到:I could not think of a means to implement mutex without closely interacting with the kernel(futex system call),并给出了一个用__sync_lock_test_and_set实现自旋锁的示例。

但是我认为__sync_lock_test_and_set也可以用来实现互斥锁:

代码语言:javascript
运行
复制
if (__sync_lock_test_and_test(&lock, 1) == 0) { 
    // we get the lock, do our work
    lock = 0; // or __sync_lock_release(&lock);
} else {
    // the lock has already been token.
}

这是互斥锁吗?

提前感谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-10-14 13:54:02

首先,Linux是特定于__sync_*内核的。在其他上下文中,您可能希望使用来自<stdatomic.h><stdatomic.h>原子类型和函数(或来自<atomic>的C++11 std::atomic )。

你的算法就其本身而言是可行的。但问题是,// the lock has already been taken的内容是什么。你在那个街区做什么?在大多数情况下,你必须做的“工作”不是可选的。您不能直接跳过它;您必须等待并在锁可用时立即执行它。本质上,您编写的只是典型互斥体的trylockunlock函数。难度更大的是lock

你想:

  1. 等待互斥,而不消耗CPU。
  2. 醒来,一有互斥,就立即取下互斥锁,没有不必要的延误。
  3. 如果多个线程正在等待互斥,那么在它们之间进行公平的仲裁,这样就不会有一个线程挨饿。

你可以通过做这样的事情来完成#1

代码语言:javascript
运行
复制
while (atomic_flag_test_and_set(&lock, 1) == 1) {
    thrd_yield(); 
    // or: thrd_sleep(short_time);
}

但是仍然会有等待线程频繁地醒来,只会测试互斥锁,发现它仍然不可用,然后继续睡觉。这可能不会占用太多的CPU时间,但它确实强制了许多不必要的上下文切换,这是不免费的。

这在#2上做得不太好,因为当互斥锁可用时,这个线程将不会立即唤醒它;它将不得不等待直到它碰巧得到另一个时间片(在thrd_yield()的情况下)或直到它的short_time过期。这不必要地减缓了你的程序。

而且它根本没有完成第三项任务。如果有几个线程在同一个互斥体上等待,它基本上是随机的,一个线程最终会占用它,而一些线程可能会比其他线程等待的时间长得多。

因此,您确实需要操作系统的支持才能正确地执行lock。操作系统可以在这个特定的互斥对象上创建一个等待线程的队列,并让它们在不可用的情况下保持休眠状态。当另一个线程解锁互斥锁时,操作系统可以选择队列中最老的线程(或应用其他一些聪明的基于优先级的算法),唤醒该线程,并且只唤醒该线程,并确保它在唤醒时确实持有互斥锁。

没有操作系统支持,除了spinlock或它的一些稍微美化的变体之外,您什么也做不了。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74069004

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档