C++ pthread的条件等待在c++;
我正在尝试使用pthread实现一个基于队列的worker。但是我对C++ pthread的条件等待在c++;,c++,pthreads,C++,Pthreads,我正在尝试使用pthread实现一个基于队列的worker。但是我对pthread\u cond\u wait()有些困惑 班主任 它永远不会从pthread\u cond\u wait()返回。我也不明白pthread\u mutex\u lock()是如何在void interrupt()方法中工作的,因为它应该已经被void condition\u lock()锁定了 编辑 我已经按照建议更改了代码中的两个更改 1. use queue.size() == 0 instead of con
pthread\u cond\u wait()
有些困惑
班主任
它永远不会从pthread\u cond\u wait()
返回。我也不明白pthread\u mutex\u lock()
是如何在void interrupt()
方法中工作的,因为它应该已经被void condition\u lock()锁定了
编辑
我已经按照建议更改了代码中的两个更改
1. use queue.size() == 0 instead of conditional variable.
2. Use mutex lock/unlock during queue.push_back()
我也不明白pthread\u mutex\u lock()
是如何在void interrupt()中工作的
不是。这导致了僵局
它应该已经被void condition\u lock()
锁定
是的。这就是为什么:
它永远不会从pthread\u cond\u wait()
返回
错误在这里:
void start_thread(Worker worker){ // worker passed by value
// thus it is a copy.
stop = false;
int status = pthread_create(&thread,NULL,
run_helper,&worker); // Address of worker passed to thread.
} // worker destroyed here.
您正在按值传递worker(从而获得一个副本)。线程正在针对此副本运行。但该副本在该函数退出时被销毁(因此互斥和cond无效)
因为这个
和工人
应该是同一件事
修复为:
void start_thread(){
stop = false;
int status = pthread_create(&thread, NULL, run_helper, this);
}
这是错误的:
void condition_lock(bool condition){
pthread_mutex_lock(&mutex);
if(condition){
// ^^^^ Should be while(<validate some invariant>)
printf("Entering conditional lock\n");
pthread_cond_wait(&cond,&mutex);
}
pthread_mutex_unlock(&mutex);
}
这个类中有两个线程。无论何时修改状态,都需要获取锁。这可以通过几种方法完成(即使修改stop
也应该在锁下完成)
从技术上讲,这不是C函数回调的有效目标
static void *run_helper(void* context){
return ((Worker *)context)->run();
}
C不知道C++ + ABI。pthreads是一个C库,因此可以作为回调传递的唯一有效指针是C函数
我也不明白pthread_mutex_lock()是如何在void interrupt()中工作的
注意:调用信号并不意味着另一个线程立即被安排执行(它只是变得可用)。您的代码处于如此紧密的循环中,因此获取退出pthread\u cond\u wait()函数所需的锁可能是一个问题
固定代码:
虽然我留下了一些无聊的补丁,但仍然需要为你做。您必须检查所有库调用的结果,以验证它们是否有效。如果它们不起作用,那么您至少可以抛出一个异常
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <vector>
#include <iostream>
using namespace std;
// LA: Callback must by C function.
extern "C" void *run_helper(void* context);
class Worker {
private:
pthread_t thread;
vector<int> queue;
bool stop;
pthread_mutex_t mutex;
pthread_cond_t cond;
public:
Worker() {
stop = false;
if (pthread_mutex_init(&mutex, NULL) != 0)
{
printf("\n mutex init failed\n");
}
if(pthread_cond_init(&cond,NULL) != 0){
printf("\n cond init failed\n");
}
}
~Worker() {
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
}
void interrupt(){
printf("Going to inturrupt\n");
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond); //broadcast also doesn't work
pthread_mutex_unlock(&mutex);
printf("inturrupted \n");
}
void *run(){
printf("run\n");
pthread_mutex_lock(&mutex);
while(!stop){
printf("Going for condition lock\n");
printf("size: %lu\n",queue.size());
// LA: Moved condition_lock() inline.
// This was because we needed the lock around
// accessing the state after the wait
// LA: Check queue size and if we are stopped after being woken
while(queue.size() == 0 && !stop){
printf("Entering conditional lock\n");
pthread_cond_wait(&cond,&mutex);
}
printf("Exit from condition lock\n");
while(queue.size() > 0){
printf("item: %d\n",queue[0]);
queue.pop_back();
}
}
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
void push(int value){
// LA: All state mutation needs to be guarded.
pthread_mutex_lock(&mutex);
queue.push_back(value);
pthread_mutex_unlock(&mutex);
}
void join(){
void *status;
pthread_join(thread,&status);
}
void stop_thread(){
// LA: All state mutation needs to be guarded.
pthread_mutex_lock(&mutex);
stop = true;
pthread_mutex_unlock(&mutex);
interrupt();
}
void start_thread(){
int status = pthread_create(&thread,NULL,run_helper,this);
}
};
extern "C" void *run_helper(void* context){
return ((Worker *)context)->run();
}
int main(){
Worker worker;
worker.start_thread();
usleep(500000);
for(int i=0;i<5;i++){
worker.push(i);
worker.interrupt();
usleep(500000);
}
worker.stop_thread();
worker.join();
printf("Thread exit\n");
return 0;
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
//LA:回调必须由C函数执行。
外部“C”void*运行辅助程序(void*上下文);
班主任{
私人:
pthread\u t线程;
向量队列;
布尔停止;
pthread_mutex_t mutex;
pthread_cond_t cond;
公众:
工人(){
停止=错误;
if(pthread\u mutex\u init(&mutex,NULL)!=0)
{
printf(“\n互斥初始化失败\n”);
}
if(pthread_cond_init(&cond,NULL)!=0){
printf(“\n cond init失败\n”);
}
}
~Worker(){
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
}
无效中断(){
printf(“转到Intrupt\n”);
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);//广播也不工作
pthread_mutex_unlock(&mutex);
printf(“Intrupted\n”);
}
void*run(){
printf(“运行\n”);
pthread_mutex_lock(&mutex);
当(!停止){
printf(“进入条件锁定\n”);
printf(“大小:%lu\n”,queue.size());
//LA:已内联移动条件_lock()。
//这是因为我们需要锁
//在等待后访问状态
//LA:检查队列大小,以及我们是否在被唤醒后停止
while(queue.size()==0&&!stop){
printf(“输入条件锁”);
pthread_cond_wait(&cond,&mutex);
}
printf(“退出条件锁定\n”);
while(queue.size()>0){
printf(“项目:%d\n”,队列[0]);
queue.pop_back();
}
}
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
无效推送(int值){
//洛杉矶:所有的状态突变都需要保护。
pthread_mutex_lock(&mutex);
队列。推回(值);
pthread_mutex_unlock(&mutex);
}
void join(){
无效*状态;
pthread_join(线程和状态);
}
无效停止_线程(){
//洛杉矶:所有的状态突变都需要保护。
pthread_mutex_lock(&mutex);
停止=真;
pthread_mutex_unlock(&mutex);
中断();
}
无效开始线程(){
int status=pthread\u create(&thread,NULL,run\u helper,this);
}
};
外部“C”void*运行辅助程序(void*上下文){
return((Worker*)上下文)->run();
}
int main(){
工人;
worker.start_线程();
美国LEEP(500000);
for(int i=0;iC++是按值传递的。您的条件锁(bool条件)
使用传递的布尔值的函数的本地副本。按照您对其进行编码的方式,它会获取(queue.size()==0)的快照
调用时,然后等待快照的副本更改。这种情况永远不会发生。@AndrewHenle在条件锁定(bool条件)
中检查if语句。第一次为true并执行pthread\u cond\u wait()。但pthread\u cond\u wait()不依赖于bool条件。bool条件是按值传递或引用不重要。不是吗?bool条件是按值传递或引用不重要。不是吗?很重要。如果按值传递,则它是另一个布尔变量。代码中的布尔值是在调用时根据队列大小计算的值,在进行调用时,您将获得该计算状态的副本-不会在每次检查该值时都重新进行该计算
void condition_lock(bool condition){
pthread_mutex_lock(&mutex);
if(condition){
// ^^^^ Should be while(<validate some invariant>)
printf("Entering conditional lock\n");
pthread_cond_wait(&cond,&mutex);
}
pthread_mutex_unlock(&mutex);
}
void push(int value){
queue.push_back(value);
}
static void *run_helper(void* context){
return ((Worker *)context)->run();
}
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond,&mutex); The call to wait releases the lock
on the mutex. When the thread is woken
up it must reaquire the lock before
the thread exits the call pthread_cond_wait()
This allows another thread to lock the
mutex modify state then call the signal
mrthod before releasing the lock.
this allows interupt() to run as expected.
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <vector>
#include <iostream>
using namespace std;
// LA: Callback must by C function.
extern "C" void *run_helper(void* context);
class Worker {
private:
pthread_t thread;
vector<int> queue;
bool stop;
pthread_mutex_t mutex;
pthread_cond_t cond;
public:
Worker() {
stop = false;
if (pthread_mutex_init(&mutex, NULL) != 0)
{
printf("\n mutex init failed\n");
}
if(pthread_cond_init(&cond,NULL) != 0){
printf("\n cond init failed\n");
}
}
~Worker() {
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
}
void interrupt(){
printf("Going to inturrupt\n");
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond); //broadcast also doesn't work
pthread_mutex_unlock(&mutex);
printf("inturrupted \n");
}
void *run(){
printf("run\n");
pthread_mutex_lock(&mutex);
while(!stop){
printf("Going for condition lock\n");
printf("size: %lu\n",queue.size());
// LA: Moved condition_lock() inline.
// This was because we needed the lock around
// accessing the state after the wait
// LA: Check queue size and if we are stopped after being woken
while(queue.size() == 0 && !stop){
printf("Entering conditional lock\n");
pthread_cond_wait(&cond,&mutex);
}
printf("Exit from condition lock\n");
while(queue.size() > 0){
printf("item: %d\n",queue[0]);
queue.pop_back();
}
}
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
void push(int value){
// LA: All state mutation needs to be guarded.
pthread_mutex_lock(&mutex);
queue.push_back(value);
pthread_mutex_unlock(&mutex);
}
void join(){
void *status;
pthread_join(thread,&status);
}
void stop_thread(){
// LA: All state mutation needs to be guarded.
pthread_mutex_lock(&mutex);
stop = true;
pthread_mutex_unlock(&mutex);
interrupt();
}
void start_thread(){
int status = pthread_create(&thread,NULL,run_helper,this);
}
};
extern "C" void *run_helper(void* context){
return ((Worker *)context)->run();
}
int main(){
Worker worker;
worker.start_thread();
usleep(500000);
for(int i=0;i<5;i++){
worker.push(i);
worker.interrupt();
usleep(500000);
}
worker.stop_thread();
worker.join();
printf("Thread exit\n");
return 0;
}