这是代码:
#include <iostream>
#include <semaphore>
#include <thread>
#include <chrono>
std::binary_semaphore sema{ 1 };
int main()
{
std::thread th([]
{
while (true)
{
sema.acquire();
std::cout << "still hold\n";
std::this_thread::sleep_for(std::chrono::milliseconds(50));
sema.release();
}
});
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "try get\n";
sema.acquire();
std::cout << "semaphore get\n";
std::this_thread::sleep_for(std::chrono::seconds(10000));
}
主线程应该能够立即获取到这个信号量,因为std::thread快速释放并重新获取信号量,此时主线程应该能够获取到这个信号量。
但实际上主线程并不是立即得到这个信号量,而是在std::thread循环了很多次之后,可能只有几次,也可能是几十次。
我使用msvc(c++20)。
那么为什么主线程不能立即获取到呢?
C++ 线程和并发模型不保证等待锁的线程的“公平性”或“饥饿自由”。根据实现的不同,释放信号量会将主线程标记为“准备运行”,但不一定会将信号量交给主线程,也不一定会立即开始执行。由于
th
线程所做的下一件事就是重新获取信号量,因此主线程没有时间来获取它。可以以保证公平的方式实现信号量,但它更复杂并且会降低性能,特别是在多核系统上。
如果你想保证这样的公平性,条件变量是更好的方法,因为它们涉及线程显式让步给每个等待获取特定互斥锁的线程。