"pthread_cond_wait" 没有等待主线程休眠,为什么?
"pthread_cond_wait" didn't wait main thread to sleep, why?
我做了一个简单的实验来测试:
- 主线程创建子线程。
- 子线程等待主线程向条件变量发出信号。
- 主线程休眠 3 秒并向 "cond" 发出信号。然后我希望子线程将从 "cond_wait" 唤醒并打印。
代码:
#include <pthread.h>
#include <unistd.h>
#include <cassert>
#include <iostream>
using namespace std;
pthread_mutex_t mt;
pthread_cond_t cond;
pthread_t tid;
void* tf(void*arg){
pthread_mutex_lock(&mt);
pthread_cond_wait(&cond, &mt);
cout<<"After main thread sleeps 3 seconds\n";
return NULL;
}
int main(){
assert(0==pthread_mutex_init(&mt,NULL));
pthread_create(&tid,NULL,tf,NULL);
sleep(3);
pthread_cond_signal(&cond);
pthread_join(tid,NULL);//Is 2nd parameter useful?
pthread_cond_destroy(&cond);
return 0;
}
但实际上,子线程会一次性打印"After main thread sleeps 3 seconds"。我哪里错了?
谢谢。
我不知道 Linux 线程函数,但在 Windows 中,您必须初始化对应于 Linux 中的 pthread_cond_t cond
的变量。
有一个名为 pthread_cond_init
的函数的联机帮助页,它似乎正是这样做的。
最重要的是,由于您将 C++ 标签附加到此问题,请使用 C++ 线程功能,而不是 pthread 库。不能保证您始终可以访问它(例如在 windows 上),而 std::thread
被设计为跨平台并且没有使用 pthread()
带来的一些烦恼库的 C 接口
其次,初始化变量,C 和 C API 很烦人。第三,您需要考虑虚假唤醒,在条件变量 wait 周围放置一个 while 循环,并为其附加一个实际条件,例如
while (not_signalled) {
pthread_cond_wait(&cond, &mt);
}
可能发生的情况是您的线程被虚假唤醒然后结束,因为您没有 while 循环来防止虚假唤醒
工作 C++ 代码
#include <thread>
#include <iostream>
#include <chrono>
using std::cout;
using std::endl;
std::mutex mtx;
std::condition_variable cv;
bool has_signalled{false};
void th_function() {
// acquire the lock
auto lck = std::unique_lock<std::mutex>{mtx};
// loop to protect against spurious wakeups
while (!has_signalled) {
// sleep
cv.wait(lck);
}
cout << "Thread has been signalled" << endl;
}
int main() {
auto th = std::thread{th_function};
// sleep for 2 seconds
std::this_thread::sleep_for(std::chrono::seconds(2));
// signal and change the variable
{
std::lock_guard<std::mutex> lck{mtx};
has_signalled = true;
}
// signal
cv.notify_one();
th.join();
}
我做了一个简单的实验来测试:
- 主线程创建子线程。
- 子线程等待主线程向条件变量发出信号。
- 主线程休眠 3 秒并向 "cond" 发出信号。然后我希望子线程将从 "cond_wait" 唤醒并打印。
代码:
#include <pthread.h>
#include <unistd.h>
#include <cassert>
#include <iostream>
using namespace std;
pthread_mutex_t mt;
pthread_cond_t cond;
pthread_t tid;
void* tf(void*arg){
pthread_mutex_lock(&mt);
pthread_cond_wait(&cond, &mt);
cout<<"After main thread sleeps 3 seconds\n";
return NULL;
}
int main(){
assert(0==pthread_mutex_init(&mt,NULL));
pthread_create(&tid,NULL,tf,NULL);
sleep(3);
pthread_cond_signal(&cond);
pthread_join(tid,NULL);//Is 2nd parameter useful?
pthread_cond_destroy(&cond);
return 0;
}
但实际上,子线程会一次性打印"After main thread sleeps 3 seconds"。我哪里错了?
谢谢。
我不知道 Linux 线程函数,但在 Windows 中,您必须初始化对应于 Linux 中的 pthread_cond_t cond
的变量。
有一个名为 pthread_cond_init
的函数的联机帮助页,它似乎正是这样做的。
最重要的是,由于您将 C++ 标签附加到此问题,请使用 C++ 线程功能,而不是 pthread 库。不能保证您始终可以访问它(例如在 windows 上),而 std::thread
被设计为跨平台并且没有使用 pthread()
带来的一些烦恼库的 C 接口
其次,初始化变量,C 和 C API 很烦人。第三,您需要考虑虚假唤醒,在条件变量 wait 周围放置一个 while 循环,并为其附加一个实际条件,例如
while (not_signalled) {
pthread_cond_wait(&cond, &mt);
}
可能发生的情况是您的线程被虚假唤醒然后结束,因为您没有 while 循环来防止虚假唤醒
工作 C++ 代码
#include <thread>
#include <iostream>
#include <chrono>
using std::cout;
using std::endl;
std::mutex mtx;
std::condition_variable cv;
bool has_signalled{false};
void th_function() {
// acquire the lock
auto lck = std::unique_lock<std::mutex>{mtx};
// loop to protect against spurious wakeups
while (!has_signalled) {
// sleep
cv.wait(lck);
}
cout << "Thread has been signalled" << endl;
}
int main() {
auto th = std::thread{th_function};
// sleep for 2 seconds
std::this_thread::sleep_for(std::chrono::seconds(2));
// signal and change the variable
{
std::lock_guard<std::mutex> lck{mtx};
has_signalled = true;
}
// signal
cv.notify_one();
th.join();
}