c++11 关于 std::condition_variable 的问题

IONPhantom 2016-10-10 12:55:59
先上代码

// 线程函数
void ThreadFunction(int iID, std::mutex& Lock, std::condition_variable& rStart)
{
std::unique_lock<std::mutex> unqLock(Lock);
rStart.wait(unqLock);
printf("Thread ID=%c\n",'A'+iID);
}
// 主函数
int _tmain(int argc, _TCHAR* argv[])
{
std::mutex Lock;
std::condition_variable con;
std::future<void> thd=std::async(std::launch::async,ThreadFunction,0,std::ref(Lock),std::ref(con));
con.notify_one();
thd.wait();
}


程序设计是这样的,当主线程发起通知,线程函数就打印自己的线程ID
也就是线程创建完毕之后线程函数在 rStart.wait(unqLock); 处等待通知,当主线程执行 con.notify_one(); 开始打印。

但是现在有个问题,当 con.notify_one(); 的时候如果没有任何等待则通知不起任何作用,要命的是程序执行起来根本无法保证 rStart.wait(unqLock); 在 con.notify_one(); 之前运行,这就造成一个结果,调用了通知可是子线程还是被block了。

有没有什么方法能够像 Windows API 的 Event 那样,即使没有 WaitForSingleObject 等待 SetEvent 也能起作用的方法呢?
...全文
553 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
lms0515032124 2017-03-15
  • 打赏
  • 举报
回复
void Thread::Suspend() { std::unique_lock<std::mutex> lock(_threadInfo._condMutex); while (_threadInfo.signal_flag == 0) { _threadInfo._cond.wait(lock); } _threadInfo.signal_flag = 0; } void Thread::Resume() { std::unique_lock<std::mutex> lock(_threadInfo._condMutex); _threadInfo.signal_flag = 1; _threadInfo._cond.notify_one(); }
fefe82 2016-10-13
  • 打赏
  • 举报
回复
引用 15 楼 P_hantom 的回复:
[quote=引用 14 楼 fefe82 的回复:] notify 只是指示“枪是否响过了”的状态发生了改变。“枪是否响过了”的状态是记录在另外一个地方的。运动员如果发现枪已经响过了,那他就不用等了。 ======================== 你的例子了,运动员还没进场(线程还没启动)枪就响了,运动员听不到。但是可以设置一个状态,让运动员虽然听不到,但是依然可以发现枪已经响过了。 ======================== 或者说这里还有另一个等待的问题,即枪必须等运动员准备好之后才能响。运动员必须等枪响之后才能跑。这显然不是一个同步操作(或者说一个 wait/notify )能解决的。
但是Windows API 的 Event 就可以做到这点。 WaitForSingleObject 先执行 SetEvent 在执行等待就可以恢复过来 SetEvent 先执行 WaitForSingleObject 再执行一样可以 这种最基本的事件对象在C++11中就没有对应的吗?[/quote] 试试这个 template< class Predicate > void wait( std::unique_lock<std::mutex>& lock, Predicate pred );
IONPhantom 2016-10-13
  • 打赏
  • 举报
回复
引用 14 楼 fefe82 的回复:
notify 只是指示“枪是否响过了”的状态发生了改变。“枪是否响过了”的状态是记录在另外一个地方的。运动员如果发现枪已经响过了,那他就不用等了。 ======================== 你的例子了,运动员还没进场(线程还没启动)枪就响了,运动员听不到。但是可以设置一个状态,让运动员虽然听不到,但是依然可以发现枪已经响过了。 ======================== 或者说这里还有另一个等待的问题,即枪必须等运动员准备好之后才能响。运动员必须等枪响之后才能跑。这显然不是一个同步操作(或者说一个 wait/notify )能解决的。
但是Windows API 的 Event 就可以做到这点。 WaitForSingleObject 先执行 SetEvent 在执行等待就可以恢复过来 SetEvent 先执行 WaitForSingleObject 再执行一样可以 这种最基本的事件对象在C++11中就没有对应的吗?
fefe82 2016-10-11
  • 打赏
  • 举报
回复
引用 12 楼 P_hantom 的回复:
[quote=引用 10 楼 fefe82 的回复:] 请问你为什么要 wait? wait 一般是在等待一个状态,比如初始化结束,比如网络连接,比如计算完成 ... 。所以线程内部,首先要检查这个状态,如果已经满足,不需要wait 。不满足时才需要 wait 。其它线程在这个状态变化的时候 notify 。 为了 wait 而 wait ,自然比较奇怪 ...
这个wait 就是要等待信号,就好像赛跑比赛,必须枪响了才可以跑,这个wait就是需求决定的[/quote] notify 只是指示“枪是否响过了”的状态发生了改变。“枪是否响过了”的状态是记录在另外一个地方的。运动员如果发现枪已经响过了,那他就不用等了。 ======================== 你的例子了,运动员还没进场(线程还没启动)枪就响了,运动员听不到。但是可以设置一个状态,让运动员虽然听不到,但是依然可以发现枪已经响过了。 ======================== 或者说这里还有另一个等待的问题,即枪必须等运动员准备好之后才能响。运动员必须等枪响之后才能跑。这显然不是一个同步操作(或者说一个 wait/notify )能解决的。
IONPhantom 2016-10-11
  • 打赏
  • 举报
回复
引用 11 楼 xsklld 的回复:
[quote=引用 4 楼 P_hantom 的回复:] [quote=引用 2 楼 xsklld 的回复:] 这个直接用互斥锁就行吧。发射线程前先加锁,main函数里需要唤醒时解锁。
能写个示例伪代码吗?[/quote]

// 线程函数
void ThreadFunction(int iID, std::mutex &my_mutex)
{
    std::lock_guard<std::mutex> lock(my_mutex);
    printf("Thread ID=%c\n",'A' + iID);
}
// 主函数
int main()
{
    std::mutex my_mutex;
    my_mutex.lock();
    std::future<void> thd = std::async(std::launch::async, ThreadFunction, 0, std::ref(lock));
    my_mutex.unlock();
    thd.wait();
}
这样?[/quote] 你这个看起来蛮靠谱的
IONPhantom 2016-10-11
  • 打赏
  • 举报
回复
引用 10 楼 fefe82 的回复:
请问你为什么要 wait? wait 一般是在等待一个状态,比如初始化结束,比如网络连接,比如计算完成 ... 。所以线程内部,首先要检查这个状态,如果已经满足,不需要wait 。不满足时才需要 wait 。其它线程在这个状态变化的时候 notify 。 为了 wait 而 wait ,自然比较奇怪 ...
这个wait 就是要等待信号,就好像赛跑比赛,必须枪响了才可以跑,这个wait就是需求决定的
xskxzr 2016-10-10
  • 打赏
  • 举报
回复
引用 4 楼 P_hantom 的回复:
[quote=引用 2 楼 xsklld 的回复:] 这个直接用互斥锁就行吧。发射线程前先加锁,main函数里需要唤醒时解锁。
能写个示例伪代码吗?[/quote]

// 线程函数
void ThreadFunction(int iID, std::mutex &my_mutex)
{
    std::lock_guard<std::mutex> lock(my_mutex);
    printf("Thread ID=%c\n",'A' + iID);
}
// 主函数
int main()
{
    std::mutex my_mutex;
    my_mutex.lock();
    std::future<void> thd = std::async(std::launch::async, ThreadFunction, 0, std::ref(lock));
    my_mutex.unlock();
    thd.wait();
}
这样?
fefe82 2016-10-10
  • 打赏
  • 举报
回复
请问你为什么要 wait? wait 一般是在等待一个状态,比如初始化结束,比如网络连接,比如计算完成 ... 。所以线程内部,首先要检查这个状态,如果已经满足,不需要wait 。不满足时才需要 wait 。其它线程在这个状态变化的时候 notify 。 为了 wait 而 wait ,自然比较奇怪 ...
ID870177103 2016-10-10
  • 打赏
  • 举报
回复
std::condition_variable除了wait还有wait_for和wait_until
ztenv 版主 2016-10-10
  • 打赏
  • 举报
回复
引用 7 楼 P_hantom 的回复:
[quote=引用 5 楼 lianshaohua 的回复:] [quote=引用 3 楼 P_hantom 的回复:] [quote=引用 1 楼 lianshaohua 的回复:] 你这种情况应该是线程还没有执行就已经通知了,加一个延时应该就好了。
就是不想加延迟,这个所谓的延迟到底延迟多少?还真不一定,因为这个只是一个实验的例子,再真是情况下并不一定立刻执行线程的。再有这个延迟的本质就是还需要一次同步,是子现成已经开始“wait”的同步,这样做太2了[/quote] 1、可以再加一个condition_variable ,当线程开始运行时,在线程内通知主线程继续执行现在condition_variable.notify() 2、给线程加一回调,当线程开始执行时,调用你的回调函数,在你的回调函数中调用 现在的notify()[/quote] C++11 就没有什么类似 Event 的方法么?[/quote] 目前不知道有没有,不过用锁可以实现类似的要求,条条大路通罗马…………
IONPhantom 2016-10-10
  • 打赏
  • 举报
回复
引用 5 楼 lianshaohua 的回复:
[quote=引用 3 楼 P_hantom 的回复:] [quote=引用 1 楼 lianshaohua 的回复:] 你这种情况应该是线程还没有执行就已经通知了,加一个延时应该就好了。
就是不想加延迟,这个所谓的延迟到底延迟多少?还真不一定,因为这个只是一个实验的例子,再真是情况下并不一定立刻执行线程的。再有这个延迟的本质就是还需要一次同步,是子现成已经开始“wait”的同步,这样做太2了[/quote] 1、可以再加一个condition_variable ,当线程开始运行时,在线程内通知主线程继续执行现在condition_variable.notify() 2、给线程加一回调,当线程开始执行时,调用你的回调函数,在你的回调函数中调用 现在的notify()[/quote] C++11 就没有什么类似 Event 的方法么?
赵4老师 2016-10-10
  • 打赏
  • 举报
回复
http://www.cplusplus.com上应该有示例代码。
ztenv 版主 2016-10-10
  • 打赏
  • 举报
回复
引用 3 楼 P_hantom 的回复:
[quote=引用 1 楼 lianshaohua 的回复:] 你这种情况应该是线程还没有执行就已经通知了,加一个延时应该就好了。
就是不想加延迟,这个所谓的延迟到底延迟多少?还真不一定,因为这个只是一个实验的例子,再真是情况下并不一定立刻执行线程的。再有这个延迟的本质就是还需要一次同步,是子现成已经开始“wait”的同步,这样做太2了[/quote] 1、可以再加一个condition_variable ,当线程开始运行时,在线程内通知主线程继续执行现在condition_variable.notify() 2、给线程加一回调,当线程开始执行时,调用你的回调函数,在你的回调函数中调用 现在的notify()
IONPhantom 2016-10-10
  • 打赏
  • 举报
回复
引用 2 楼 xsklld 的回复:
这个直接用互斥锁就行吧。发射线程前先加锁,main函数里需要唤醒时解锁。
能写个示例伪代码吗?
IONPhantom 2016-10-10
  • 打赏
  • 举报
回复
引用 1 楼 lianshaohua 的回复:
你这种情况应该是线程还没有执行就已经通知了,加一个延时应该就好了。
就是不想加延迟,这个所谓的延迟到底延迟多少?还真不一定,因为这个只是一个实验的例子,再真是情况下并不一定立刻执行线程的。再有这个延迟的本质就是还需要一次同步,是子现成已经开始“wait”的同步,这样做太2了
xskxzr 2016-10-10
  • 打赏
  • 举报
回复
这个直接用互斥锁就行吧。发射线程前先加锁,main函数里需要唤醒时解锁。
ztenv 版主 2016-10-10
  • 打赏
  • 举报
回复
你这种情况应该是线程还没有执行就已经通知了,加一个延时应该就好了。

64,266

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧