有没有办法确保被阻塞的线程按照被阻塞的顺序唤醒?我在某处读到这将被称为“强锁”,但我没有找到任何资源。
在 Mac OS X 上,可以设计一个 FIFO 队列来存储阻塞线程的所有线程 ID,然后使用漂亮的函数 pthread_cond_signal_thread_np()
来唤醒一个特定的线程 - 这显然不是-标准和非可移植。
我能想到的一种方法是使用类似的队列,并在 unlock()
点向所有线程发送 broadcast()
并让它们检查哪一个是下一个。
但这会导致大量开销。
解决该问题的一种方法是将 packaged_task 发送到队列并让它按顺序处理它们。但这对我来说更像是一种解决方法而不是解决方案。
编辑:
正如评论所指出的,这个问题听起来可能无关紧要,因为原则上没有保证锁定尝试的顺序。
作为澄清:
我有一个我称之为 ConditionLockQueue 的东西,它与 Cocoa 库中的 NSConditionLock 类非常相似,但它维护一个阻塞线程的 FIFO 队列,而不是一个或多或少的随机池。
基本上任何线程都可以“排队”(有或没有特定“条件”的要求 - 一个简单的整数值 - 要满足)。然后线程被放置在队列中并阻塞,直到它是队列中满足条件的最前面的元素。
这提供了一种非常灵活的同步方式,我发现它在我的程序中非常有用。
现在我真正需要的是一种唤醒具有特定 id 的特定线程的方法。
但这些问题几乎都是一样的。
最佳答案
构建一个使用编号票证的锁对象非常容易,以确保其完全公平(按照线程首先尝试获取锁的顺序授予锁):
#include <mutex>
#include <condition_variable>
class ordered_lock {
std::condition_variable cvar;
std::mutex cvar_lock;
unsigned int next_ticket, counter;
public:
ordered_lock() : next_ticket(0), counter(0) {}
void lock() {
std::unique_lock<std::mutex> acquire(cvar_lock);
unsigned int ticket = next_ticket++;
while (ticket != counter)
cvar.wait(acquire);
}
void unlock() {
std::unique_lock<std::mutex> acquire(cvar_lock);
counter++;
cvar.notify_all();
}
};
编辑
修正奥拉夫的建议:
#include <mutex>
#include <condition_variable>
#include <queue>
class ordered_lock {
std::queue<std::condition_variable *> cvar;
std::mutex cvar_lock;
bool locked;
public:
ordered_lock() : locked(false) {};
void lock() {
std::unique_lock<std::mutex> acquire(cvar_lock);
if (locked) {
std::condition_variable signal;
cvar.emplace(&signal);
signal.wait(acquire);
} else {
locked = true;
}
}
void unlock() {
std::unique_lock<std::mutex> acquire(cvar_lock);
if (cvar.empty()) {
locked = false;
} else {
cvar.front()->notify_one();
cvar.pop();
}
}
};
关于c++ - 在 C++11 中创建一个保留锁定尝试顺序的锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14792016/