Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ms-access/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ pthread的条件等待在c++;_C++_Pthreads - Fatal编程技术网

C++ pthread的条件等待在c++;

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实现一个基于队列的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 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;
}