C++ 如何使用pthreads以智能方式将变量共享给线程?

C++ 如何使用pthreads以智能方式将变量共享给线程?,c++,multithreading,pthreads,C++,Multithreading,Pthreads,我想用智能线程使用p螺纹来同步C++中的线程。 我有一个全局变量: int Resources = 0; 我有两个线程函数: void *incResources(void *arg) { while(1) { pthread_mutex_lock (&resourcesMutex); Resources += 2; pthread_mutex_unlock (&resourcesMutex); } pthread_exit((

我想用智能线程使用p螺纹来同步C++中的线程。 我有一个全局变量:

int Resources = 0;
我有两个线程函数:

void *incResources(void *arg)
{
   while(1)
   {
     pthread_mutex_lock (&resourcesMutex);
     Resources += 2;
     pthread_mutex_unlock (&resourcesMutex);
   }

pthread_exit((void*) 0);
}

void *consumeResources(void *arg)
{
   while(1)
   {
     pthread_mutex_lock (&resourcesMutex);
     Resources--;
     pthread_mutex_unlock (&resourcesMutex);
   }
   pthread_exit((void*) 0);
 }
在main函数中,我初始化了两个消耗线程和一个递增线程:

pthread_mutex_init(&resourcesMutex, NULL);

pthread_create(&callThd[0], &attr, incResources, (void *)i);
pthread_create(&callThd[1], &attr, consumeResources, (void *)i);
pthread_create(&callThd[2], &attr, consumeResources, (void *)i);
我觉得这是不够的,可以做得更好。你能给我一些建议吗?我尝试使用“等待”,但我不明白:/
谢谢

>你寻找好的和C++的方式,我强烈建议阅读和离开pTrk使用期货和类似的高级事物。如果你一定要用手工摆线,你也可以找到很好的例子


您的问题陈述过于模糊,无法给出合理的建议——好线程的基本思想是根本没有共享状态,对于像您这样的握手情况,可能需要使用为此目的而设计的同步队列

一种更聪明的方法是使用
std::mutex
std::thread
(或Boost等价物),这样就不需要手动解锁mutex

条件变量将允许使用者阻塞(不浪费CPU周期),直到有可用的工作:

struct Resource
{
  int value;
  std::mutex mx;
  std::condition_variable cv;
};

void incResources(Resource& res)
{
   while(1)
   {
     {
       std::lock_guard<std::mutex> l(res.mx);
       res.value += 2;
     }
     res.cv.notify_all();
   }
}

void consumeResources(Resource& res)
{
   while(1)
   {
     std::unique_lock<std::mutex> l(res.mx);
     while (res.value == 0)
       res.cv.wait(l);
     res.value--;
   }
}

我认为如果你使用C++,没有理由喜欢在p++上使用C++来代替C++ 11代码> STD::线程< /C>和STL同步类。


如果你不能使用C++ 11标准,你应该把PrPro本地接口包到合理的C++类表示(参见或实现)。

< P>看起来你正在试图实现一个生产者和消费者,++=线程创建工作(要减少的数字)和消费者拿走它们。 不要让消费者像那样处于一个琐碎的旋转循环中,而是看一看条件变量

std::queue<Job*> queue;
pthread_mutex mutex;
pthread_cond cond;

void AddJob(Job* job) {
    pthread_mutex_lock(&mutex);
    queue.push_back(job);
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
}

void* QueueWorker(void* /*threadInfo*/) {
    Job* job = NULL;
    for (;;) {
        pthread_mutex_lock(&mutex);
        while ( queue.empty() ) {
            // unlock the mutex until the cond is signal()d or broadcast() to.
            // if this call succeeds, we will have the mutex locked again on the other side.
            pthread_cond_wait(&cond, &mutex);
        }
        // take the first task and then release the lock.
        job = queue.pop();
        pthread_mutex_unlock(&mutex);

        if ( job != NULL )
           job->Execute();
    }

    return NULL;
}
std::队列;
pthread_mutex mutex;
pthread_cond;
void AddJob(作业*作业){
pthread_mutex_lock(&mutex);
队列。推回(作业);
pthread_cond_信号(&cond);
pthread_mutex_unlock(&mutex);
}
void*QueueWorker(void*/*threadInfo*/){
Job*Job=NULL;
对于(;;){
pthread_mutex_lock(&mutex);
while(queue.empty()){
//解锁互斥锁,直到条件为signal()d或broadcast()to。
//如果调用成功,我们将在另一端再次锁定互斥锁。
pthread_cond_wait(&cond,&mutex);
}
//执行第一个任务,然后释放锁。
job=queue.pop();
pthread_mutex_unlock(&mutex);
如果(作业!=NULL)
作业->执行();
}
返回NULL;
}
这可以扩展到多个消费者

另一方面,虽然熟悉pthreads实现可能很有用,但您可能应该看看可用的线程包装器之一。C++11引入了std::thread和std::mutex,许多人都对boost信誓旦旦,但就我个人而言,我发现OpenSceneGraph团队的“OpenThreads”库是使用起来最简单、最优雅的库之一

编辑:这是一个完整的工作实现,尽管有一些人为的结束运行的机制

#include <queue>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static int jobNo = 0;
class Job {
public:
    Job() : m_i(++jobNo) { printf("Created job %d.\n", m_i); }
    int m_i;
    void Execute() { printf("Job %d executing.\n", m_i); usleep(500 * 1000); }
};

std::queue<Job*> queue;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void AddJob(Job* job) {
    pthread_mutex_lock(&mutex);
    queue.push(job);
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
}

void* QueueWorker(void* /*threadInfo*/) {
    Job* job = NULL;
    for (;;) {
        pthread_mutex_lock(&mutex);
        while ( queue.empty() ) {
            // unlock the mutex until the cond is signal()d or broadcast() to.
            // if this call succeeds, we will have the mutex locked again on the other side.
            pthread_cond_wait(&cond, &mutex);
        }
        // take the first task and then release the lock.
        job = queue.front();
        queue.pop();
        pthread_mutex_unlock(&mutex);

        if ( job == NULL ) {
            // in this demonstration, NULL ends the run, so forward to any other threads.
            AddJob(NULL);
            break;
        }
        job->Execute();
        delete job;
    }
    return NULL;
}

int main(int argc, const char* argv[]) {
    pthread_t worker1, worker2;
    pthread_create(&worker1, NULL, &QueueWorker, NULL);
    pthread_create(&worker2, NULL, &QueueWorker, NULL);

    srand(time(NULL));

    // queue 5 jobs with delays.
    for ( size_t i = 0; i < 5; ++i ) {
        long delay = (rand() % 800) * 1000;
        printf("Producer sleeping %fs\n", (float)delay / (1000*1000));
        usleep(delay);
        Job* job = new Job();
        AddJob(job);
    }
    // 5 more without delays.
    for ( size_t i = 0; i < 5; ++i ) {
        AddJob(new Job);
    }
    // null to end the run.
    AddJob(NULL);

    printf("Done with jobs.\n");
    pthread_join(worker1, NULL);
    pthread_join(worker2, NULL);

    return 0;
}
#包括
#包括
#包括
#包括
#包括
静态int-jobNo=0;
班级作业{
公众:
Job():m_i(++jobNo){printf(“已创建作业%d.\n”,m_i);}
国际货币基金组织;
void Execute(){printf(“作业%d正在执行。\n”,m_i);usleep(500*1000);}
};
std::队列;
pthread\u mutex\u t mutex=pthread\u mutex\u初始值设定项;
pthread_cond_t cond=pthread_cond_初始值设定项;
void AddJob(作业*作业){
pthread_mutex_lock(&mutex);
队列推送(作业);
pthread_cond_信号(&cond);
pthread_mutex_unlock(&mutex);
}
void*QueueWorker(void*/*threadInfo*/){
Job*Job=NULL;
对于(;;){
pthread_mutex_lock(&mutex);
while(queue.empty()){
//解锁互斥锁,直到条件为signal()d或broadcast()to。
//如果调用成功,我们将在另一端再次锁定互斥锁。
pthread_cond_wait(&cond,&mutex);
}
//执行第一个任务,然后释放锁。
job=queue.front();
queue.pop();
pthread_mutex_unlock(&mutex);
如果(作业==NULL){
//在本演示中,NULL结束运行,因此将转发到任何其他线程。
AddJob(空);
打破
}
作业->执行();
删除作业;
}
返回NULL;
}
int main(int argc,const char*argv[]{
pthread_t worker1,worker2;
pthread_create(&worker1,NULL,&QueueWorker,NULL);
pthread_create(&worker2,NULL,&QueueWorker,NULL);
srand(时间(空));
//排队等待5个有延迟的作业。
对于(尺寸i=0;i<5;++i){
长延迟=(rand()%800)*1000;
printf(“生产者睡眠%fs\n”,(浮动)延迟/(1000*1000));
usleep(延迟);
作业*作业=新作业();
AddJob(job);
}
//5个以上,没有延误。
对于(尺寸i=0;i<5;++i){
AddJob(新工作);
}
//null以结束运行。
AddJob(空);
printf(“已完成作业。\n”);
pthread_join(worker1,NULL);
pthread_join(worker2,NULL);
返回0;
}

您真正的问题是什么?我相信你不仅仅是在增加和减少一个变量。线程和效率更多地取决于消费者和生产者的问题/工作类型,而不仅仅取决于他们的数量。可能一比一的比例是有意义的。我们没有足够的信息来提供明智的见解。例:如果您所做的全部工作都是递增和递减一个int,那么您似乎有1个太多的使用者。:)我更喜欢使用类并将实例传递给线程函数,而不是使用一些全局引用。这看起来像是一个典型的生产者/消费者问题,通常使用
队列
存储消息,使用
互斥体/condition\u变量
对进行同步来解决。然而,正如@ChrisCM所说,我们没有足够的信息来giv
#include <queue>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static int jobNo = 0;
class Job {
public:
    Job() : m_i(++jobNo) { printf("Created job %d.\n", m_i); }
    int m_i;
    void Execute() { printf("Job %d executing.\n", m_i); usleep(500 * 1000); }
};

std::queue<Job*> queue;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void AddJob(Job* job) {
    pthread_mutex_lock(&mutex);
    queue.push(job);
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
}

void* QueueWorker(void* /*threadInfo*/) {
    Job* job = NULL;
    for (;;) {
        pthread_mutex_lock(&mutex);
        while ( queue.empty() ) {
            // unlock the mutex until the cond is signal()d or broadcast() to.
            // if this call succeeds, we will have the mutex locked again on the other side.
            pthread_cond_wait(&cond, &mutex);
        }
        // take the first task and then release the lock.
        job = queue.front();
        queue.pop();
        pthread_mutex_unlock(&mutex);

        if ( job == NULL ) {
            // in this demonstration, NULL ends the run, so forward to any other threads.
            AddJob(NULL);
            break;
        }
        job->Execute();
        delete job;
    }
    return NULL;
}

int main(int argc, const char* argv[]) {
    pthread_t worker1, worker2;
    pthread_create(&worker1, NULL, &QueueWorker, NULL);
    pthread_create(&worker2, NULL, &QueueWorker, NULL);

    srand(time(NULL));

    // queue 5 jobs with delays.
    for ( size_t i = 0; i < 5; ++i ) {
        long delay = (rand() % 800) * 1000;
        printf("Producer sleeping %fs\n", (float)delay / (1000*1000));
        usleep(delay);
        Job* job = new Job();
        AddJob(job);
    }
    // 5 more without delays.
    for ( size_t i = 0; i < 5; ++i ) {
        AddJob(new Job);
    }
    // null to end the run.
    AddJob(NULL);

    printf("Done with jobs.\n");
    pthread_join(worker1, NULL);
    pthread_join(worker2, NULL);

    return 0;
}