多生产者 - 消费者执行的效率

时间:2016-07-03 14:55:09

标签: c++ multithreading mutex semaphore producer-consumer

我试图与多个制作人和消费者制作代码。我为生产者和消费者创建了多线程,并使用信号量进行同步。该代码与单个生产者和消费者一起工作正常。

我面临的问题是,在程序执行一段时间后,只有consumer1和producer1参与了这个过程。我无法理解其他生产者和消费者的情况。

我还想知道如何使多生产者 - 消费者问题有效?在所有生产者和消费者分别获得平等生产和消费机会的意义上是否有效? C ++代码(它包含很多C):

#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <queue>
using namespace std;
sem_t empty;
sem_t full;
int cnt = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
queue<int> q;
void *producer(void *a)
{   
    int *num = (int *)a;
    while(1) {
        sem_wait(&empty);
        pthread_mutex_lock(&mutex);
        cnt = cnt+1;
        q.push(cnt);
        cout<<cnt<<" item produced by producer "<<(*num+1)<<endl;
        pthread_mutex_unlock(&mutex);
        sem_post(&full);
        sleep(1);
    }
}
void *consumer(void *a)
{   
    int *num = (int *)a;
    while(1) {
        sem_wait(&full);
        pthread_mutex_lock(&mutex);
        cout<<q.front()<<" item consumed by consumer "<<(*num+1)<<endl;
        q.pop();
        pthread_mutex_unlock(&mutex);
        sem_post(&empty);
        sleep(1);
    }
}
int main()
{   
    pthread_t p[5];
    pthread_t c[5];
    sem_init(&empty,0,5);
    sem_init(&full,0,0);
    int i;
    for(i = 0; i < 5; i++) {
        pthread_create(&p[i],NULL,producer,(void *)(&i));
    }
    for(i = 0; i < 5; i++) {
        pthread_create(&c[i],NULL,consumer,(void *)(&i));
    }
    for(i = 0; i < 5; i++) {
        pthread_join(p[i],NULL);
        pthread_join(c[i],NULL);
    }
}

更新的代码:

#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <queue>
#include <map>
using namespace std;
sem_t empty;
sem_t full;
int cnt = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
map<pthread_t,int> mc,mp;
queue<int> q;
void *producer(void *a)
{   
    while(1) {
        sem_wait(&empty);
        pthread_mutex_lock(&mutex);
        cnt = cnt+1;
        q.push(cnt);
        cout<<cnt<<" item produced by producer "<<mp[pthread_self()]<<endl;
        pthread_mutex_unlock(&mutex);
        sem_post(&full);
        sleep(1);
    }
}
void *consumer(void *a)
{   
    while(1) {
        sem_wait(&full);
        pthread_mutex_lock(&mutex);
        cout<<q.front()<<" item consumed by consumer "<<mc[pthread_self()]<<endl;
        q.pop();
        pthread_mutex_unlock(&mutex);
        sem_post(&empty);
        sleep(1);
    }
}
int main()
{   
    pthread_t p[5];
    pthread_t c[5];
    sem_init(&empty,0,5);
    sem_init(&full,0,0);
    int i;
    pthread_mutex_lock(&mutex);
    for(i = 0; i < 5; i++) {
        pthread_create(&p[i],NULL,producer,NULL);
        pthread_create(&c[i],NULL,consumer,NULL);
        mc[c[i]] = i+1;
        mp[p[i]] = i+1; 
    }
    pthread_mutex_unlock(&mutex);
    for(i = 0; i < 5; i++) {
        pthread_join(p[i],NULL);
        pthread_join(c[i],NULL);
    }
}

1 个答案:

答案 0 :(得分:2)

简短回答

线程确实以相同的机会执行,但它们只打印出一个不属于他们的标识符。

详细说明

在每个线程中保留一个指针num到线程号。它是保存该值的指针,而不是值本身。所以所有线程指向同一个计数器,想要找到自己的标识符。

每次访问*num时,您都无法访问i启动线程时的值,而是访问其当前值。

不幸的是,在main()的每个循环中,您都重用了变量i。所以最后一个循环,你将i设置回0,并等待第一个线程加入。但是所有这些线程都会永远循环,所以循环很难有机会超越这个初始的0值。因此,每个线程都认为此时的数字*num+1为1。

请注意您在注释中指出的创建竞争条件的方式:所有使用者和生产者线程取消引用指针,访问互斥保护区域中的同一变量。还行吧。但是当他们正在读取变量时,主线程仍然可以在任何锁之外更改共享变量。这绝对是种族风险。

解决方法

std::thread允许您通过walue传递i,以便每个线程都有自己的未更改的is id副本。

使用pthreads,您必须传递指向值的指针。不幸的是,即使你在线程的开头做了指向的值的本地副本,你仍然处于竞争状态。

快速解决方法,观察哪个线程正在做的工作就是打印输出pthread_self()的结果(参见here如何操作)。或者将id存储在int数组中,并将地址传递给该数组中的唯一元素。