C 多线程、消费者和生产者

C 多线程、消费者和生产者,c,linux,multithreading,unix,C,Linux,Multithreading,Unix,我对多线程有一个问题,因为我不熟悉这个主题。下面的代码是我从大学得到的代码。它有几个版本,我理解其中的大部分。但是我并不真正理解nready.nready变量和所有这些线程条件。有人能描述一下这两个在这里是如何工作的吗?为什么我不能通过互斥来同步线程的工作呢 #include "unpipc.h" #define MAXNITEMS 1000000 #define MAXNTHREADS 100 /* globals shared by thread

我对多线程有一个问题,因为我不熟悉这个主题。下面的代码是我从大学得到的代码。它有几个版本,我理解其中的大部分。但是我并不真正理解nready.nready变量和所有这些线程条件。有人能描述一下这两个在这里是如何工作的吗?为什么我不能通过互斥来同步线程的工作呢

#include    "unpipc.h"

#define MAXNITEMS       1000000
#define MAXNTHREADS         100

    /* globals shared by threads */
int     nitems;             /* read-only by producer and consumer */
int     buff[MAXNITEMS];

struct {
pthread_mutex_t mutex;
pthread_cond_t  cond;
int             nput;
int             nval;
int             nready;
} nready = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER };

void    *produce(void *), *consume(void *);

/* include main */
int
main(int argc, char **argv)
{
int         i, nthreads, count[MAXNTHREADS];
pthread_t   tid_produce[MAXNTHREADS], tid_consume;

if (argc != 3)
    err_quit("usage: prodcons5 <#items> <#threads>");
nitems = min(atoi(argv[1]), MAXNITEMS);
nthreads = min(atoi(argv[2]), MAXNTHREADS);

Set_concurrency(nthreads + 1);
    /* 4create all producers and one consumer */
for (i = 0; i < nthreads; i++) {
    count[i] = 0;
    Pthread_create(&tid_produce[i], NULL, produce, &count[i]);
}
Pthread_create(&tid_consume, NULL, consume, NULL);

    /* wait for all producers and the consumer */
for (i = 0; i < nthreads; i++) {
    Pthread_join(tid_produce[i], NULL);
    printf("count[%d] = %d\n", i, count[i]);    
}
Pthread_join(tid_consume, NULL);

exit(0);
}
/* end main */

void *
produce(void *arg)
{
    for ( ; ; ) {
    Pthread_mutex_lock(&nready.mutex);
    if (nready.nput >= nitems) {
        Pthread_mutex_unlock(&nready.mutex);
        return(NULL);       /* array is full, we're done */
    }
    buff[nready.nput] = nready.nval;
    nready.nput++;
    nready.nval++;
    nready.nready++;
    Pthread_cond_signal(&nready.cond);
    Pthread_mutex_unlock(&nready.mutex);
    *((int *) arg) += 1;
}
}

/* include consume */
void *
consume(void *arg)
{
int     i;

for (i = 0; i < nitems; i++) {
    Pthread_mutex_lock(&nready.mutex);
    while (nready.nready == 0)
        Pthread_cond_wait(&nready.cond, &nready.mutex);
    nready.nready--;
    Pthread_mutex_unlock(&nready.mutex);

    if (buff[i] != i)
        printf("buff[%d] = %d\n", i, buff[i]);
}
return(NULL);
}
/* end consume */
#包括“unpipc.h”
#定义最大值1000000
#定义MAXNTHREADS 100
/*线程共享的全局*/
int nitems;/*生产者和消费者只读*/
int buff[MAXNITEMS];
结构{
pthread_mutex_t mutex;
pthread_cond_t cond;
int nput;
国际nval;
国际研究所;
}nready={PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER};
无效*生产(无效*)、*消耗(无效*);
/*包括主要*/
int
主(内部argc,字符**argv)
{
int i,nthreads,count[MAXNTHREADS];
pthread_t tid_product[MAXNTHREADS],tid_consume;
如果(argc!=3)
err_quit(“用法:prodcons5”);
nitems=min(atoi(argv[1]),MAXNITEMS);
nthreads=min(atoi(argv[2]),MAXNTHREADS);
设置_并发(nthreads+1);
/*4创建所有生产者和一个消费者*/
对于(i=0;i=nitems){
Pthread_mutex_unlock(&nready.mutex);
return(NULL);/*数组已满,完成*/
}
buff[nready.nput]=nready.nval;
nput++;
nready.nval++;
nredy.nredy++;
Pthread_cond_信号(&nready.cond);
Pthread_mutex_unlock(&nready.mutex);
*((int*)arg)+=1;
}
}
/*包括消费*/
空虚*
消耗(无效*参数)
{
int i;
对于(i=0;i
此结构的全部要点是确保在执行相应的操作(nready.nready-->)时,条件(nready.nready==0)仍然为真,或者如果条件不满足,则在不使用CPU时间的情况下等待条件满足

您只能使用互斥锁来检查条件是否正确,并以原子方式执行相应的操作。但是如果条件不满足,你就不知道该怎么办。等待直到什么时候?再检查一遍?释放互斥锁,然后立即重新检查?那会浪费CPU时间

pthread_cond_signal()和pthread_cond_wait()就是用来解决这个问题的。你应该检查他们的手册页

简单地说,pthread_cond_wait所做的是将调用线程置于睡眠状态,并以原子方式释放互斥,直到发出信号为止。这是一个阻塞函数。然后可以通过从不同线程调用信号或广播来重新调度线程。当线程收到信号时,它会再次获取互斥体并退出wait()函数

在这一点上你知道

  • 你的情况真实可靠
  • 您持有互斥锁
  • 因此,您可以对数据执行任何需要执行的操作

    不过要小心,如果您不确定另一个线程是否会发出信号,就不应该调用wait。这是死锁的一个非常常见的来源

    当一个线程收到一个信号时,它会被放入准备调度的线程列表中。当线程实际执行时,您的条件(即nread.nready==0)可能再次为false。因此需要while(重新检查线程是否唤醒)

    1)
    struct nready
    nready
    字段用于确定准备使用的任务数量,即数组
    buff
    中的剩余任务。
    nredy.nredy++语句仅在生产者将一个新项放入数组
    buff
    ,并且
    nready.nready-->时执行buff
    中获取项目时,才会执行code>。使用is变量,程序员可以始终跟踪还有多少任务要处理

    (二)

    上面的语句是常见的条件变量用法。你可以查一下 有关条件变量的更多信息


    为什么不能只使用互斥?您可以反复轮询互斥锁。显然,这是CPU时间消耗,可能会极大地影响系统性能。相反,当
    buff
    中没有更多项目时,您希望消费者在睡眠中等待,当制作人将新项目放入
    buff
    时,消费者被唤醒。条件变量在此充当此角色。当没有项目时(nready.nready==0),
    pthread\u cond\u wait()
    函数将当前线程置于睡眠状态,节省宝贵的cpu时间。当新项目到达时,
    Pthread\u cond\u signal()
    会唤醒消费者。

    大多数进程都会被200个线程拖下水。函数调用什么:Set\u并发性(nthreads+1);真的吗?为什么标准的pthread函数名被替换为相同拼写但不同的大写函数呢?再一次,这不是我的代码。我被赋予学习和理解线程的任务。@user3629249只有在所有200个线程都希望同时运行并且可用的CPU远远少于200个时才使用。另一方面,有很多例子表明程序运行数百甚至数千个线程,只要大多数程序在等待某些事件时花大部分时间睡觉(传入网络c)
    "But I don't really understand the nready.nready variable"
    
    this results from the struct instance being named 'nready' and there 
    is a field within the struct named 'nready'
    
    IMO: a very poor design to have two different objects being given the same name
    
    the nready field of the nready struct seems to be keeping track of the number of 
    items that have been 'produced'
    
    pthread_mutex_lock(&nready.mutex);
    while (nready.nready == 0)
        pthread_cond_wait(&nready.cond, &nready.mutex);
    nready.nready--;
    pthread_mutex_unlock(&nready.mutex);
    
    pthread_mutex_lock(&nready.mutex);
    while (nready.nready == 0)
        pthread_cond_wait(&nready.cond, &nready.mutex);
    nready.nready--;
    pthread_mutex_unlock(&nready.mutex);