如果我调用 wait 通知的条件变量会发生什么
What happens if i call wait on a notified condition variable
假设我有两个线程和一个共享的 c++ 11 条件变量。如果线程 1 调用通知并在该线程 2 调用等待之后会发生什么?thread2 会永远阻塞还是由于线程 1 调用通知而继续工作?
编辑:
enum bcLockOperation
{
bcLockOperation_Light = -1,
bcLockOperation_Medium = 50,
bcLockOperation_Heavy = 1
}
class BC_COREDLL_EXP bcCustomMutex
{
private:
bcCustomMutex(const bcCustomMutex&);
bcCustomMutex& operator=(const bcCustomMutex&);
protected:
bcAtomic<int> mFlag;
bcMutex mMutex;
bcConditionVariable mCond;
public:
bcCustomMutex() { bcAtomicOperation::bcAtomicInit(mFlag, 0); };
~bcCustomMutex() {};
void lock(bcLockOperation pLockOperation = bcLockOperation_Medium)
{
bcINT32 lNewLoopCount = static_cast<bcINT32>(pLockOperation);
bcINT32 lLoopCounter = 0;
bcINT32 lExpected = 0;
bcINT32 lLoopCount = bcAtomicOperation::bcAtomicLoad(mFlag, bcMemoryOrder_Relaxed);
while (true)
{
while(bcAtomicOperation::bcAtomicLoad(mFlag, bcMemoryOrder_Relaxed) != 0 && lLoopCounter != lLoopCount)
++lLoopCounter;
bcAtomicOperation::bcAtomicCompareExchangeStrong(
mFlag,
&lExpected,
lNewLoopCount,
bcMemoryOrder_Acquire,
bcMemoryOrder_Relaxed);
if(lExpected == 0)
{
return;
}
else if(lLoopCounter == lLoopCount)
{
bcLockGuard<bcMutex> lGuard(mMutex);
mCond.wait(mMutex);
}
else
{
continue;
}
}
void UnLock()
{
bcAtomicOperation::bcAtomicStore(mFlag, 0, bcMemoryOrder_Relaxed);
bcUniqueLock<bcMutex> lGuard(mMutex);
mCond.notifyOne();
}
bcBOOL TryLock()
{
};
};
我想编写一个自定义互斥锁,以便每个线程都可以提供一个参数,该参数表示当前线程要执行的操作的复杂性。如果操作的复杂性较低,则其他线程将像旋转锁一样处于循环中,但如果操作的复杂性中等,则每个线程将迭代 50 次,然后按条件变量休眠,如果操作非常复杂,其他线程将直接进入睡眠状态。
现在假设 thread1 锁定此互斥锁,并且 thread2 由于其循环计数器到达其末尾而等待,并且在锁定条件变量的互斥锁之前,thread1 调用会通知条件变量。现在 thread2 将休眠,直到另一个线程锁定自定义互斥锁,然后对其调用 unlock 。
我是多线程的新手,我想学习。我知道我的类可能包含错误或可能完全错误,但是有没有办法纠正这个问题或编写这种互斥锁的好算法。
Thread2 将阻塞,直到有人调用通知。用于通知调用时正在等待的释放线程的调用。如果没有线程在等待,它们什么也不做。他们没有得救。
决定等待的代码和决定通知的代码共享相同的互斥锁。因此,线程 2 永远不会"错过"来自线程 1 的通知。
下面是经典的基于锁的并发队列示例:
void push(int x)
{
lock_guard<mutex> guard{queue_mutex};
thequeue.push(x);
not_empty_condition.notify_one();
}
int pop()
{
unique_lock<mutex> guard{queue_mutex};
not_empty_condition.wait(guard, []{ return !thequeue.empty(); } );
int x = thequeue.front();
thequeue.pop();
return x;
}
假设线程 1 和线程 2 分别运行push()
和pop()
。一次只有一个将处于关键部分。
如果 thread2 有锁,它要么从不等待,因为队列不为空(因此"丢失"通知是无害的(,要么它坐在那里等待通知(不会丢失(。
如果 thread1 得到了锁,它会在队列中放置一个元素;如果 thread2 正在等待,它将得到正确的通知;如果 thread2 仍在等待互斥锁,它将永远不会等待,因为队列中至少有一个元素,因此丢失通知是无害的。
以这种方式,只有在一开始不需要通知时,通知才会丢失。
现在,如果您对条件变量有不同的用法,其中"丢失"通知会产生任何后果,我相信您要么有竞争条件,要么完全使用了错误的工具。
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在 .h 文件中的类中声明静态变量和在.cpp文件中声明"global"变量有什么区别
- 未初始化的变量有什么危险
- 在C/C++中将变量名定义为__00000001有什么好处吗
- 我可以在这里替换什么,因为我不能在 C# 中使用隐式变量的 lambda 函数?
- Visual C++: MSVC vs. GCC+CLANG: 处理 lambda 捕获类成员变量,正确的方法是什么?
- 存储变量的更有效方法是什么?
- 变量 BitMask 在函数 CeilLog2 中的实际效果是什么?
- 这个变量在 C++ 中的范围是什么?
- 从二进制流中读取时,将双精度变量的地址转换为 char* 意味着什么?
- 变量按什么顺序相乘
- 与普通变量相比,仅仅读取原子变量的性能有什么不同吗
- 使用 gtest 框架在单元测试代码中检查目标对象的私有变量的最佳实践是什么?
- C++在变量的内存地址上做什么来"deallocate"它?
- 有什么方法可以使用 int 变量来完成组件名称吗?
- 从"LLONG_MAX 秒"构造 std::chrono::毫秒变量时发生了什么?
- 将共享指针传递给函数参数 - 将其分配给局部变量的正确方法是什么
- 正在连接的等待条件变量的线程会发生什么情况?
- 当使用Lua作为嵌入式语言(比如c++)时,有什么简单/方便的方法可以找到变量在Lua中的定义位置吗
- 什么是变量均值'int border = borderType & ~BORDER_ISOLATED'?