我遇到多线程问题,因为我是这个主题的新手。下面的代码是我在大学提供的代码。这是几个版本,我理解他们中的大多数。但我真的不了解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 */
答案 0 :(得分:1)
pthread_mutex_lock(&nready.mutex);
while (nready.nready == 0)
pthread_cond_wait(&nready.cond, &nready.mutex);
nready.nready--;
pthread_mutex_unlock(&nready.mutex);
这个结构的重点是保证条件(nready.nready == 0)在你执行相应的动作(nready.nready--)或者 - 如果条件不满意 - 时仍然是真的 - 等待直到它没有使用CPU时间。
您可以仅使用互斥锁,检查条件是否正确并以原子方式执行相应的操作。但如果条件不满意,你就不会知道该怎么做。等待?到什么时候?再检查一下?释放互斥锁并在之后立即重新检查?这会浪费CPU时间......
pthread_cond_signal()和pthread_cond_wait()就是为了解决这个问题。你应该查看他们的手册页。
简单地说,pthread_cond_wait的作用是,它将调用线程置于休眠状态并以原子方式释放互斥锁,直到它发出信号。所以这是一个阻塞功能。然后可以通过调用来自不同线程的信号或广播来重新调度该线程。当线程发出信号时,它会再次获取互斥锁并退出wait()函数。
至此,你知道
因此,您可以对数据执行任何操作。
但是要小心,如果你不确定另一个线程会发出信号,你就不应该等待。这是一个非常常见的死锁来源。
当线程收到信号时,它会放在准备好安排的线程列表中。当线程实际执行时,您的条件(即nread.nready == 0)可能再次为假。因此while(重新检查线程是否被唤醒)。
答案 1 :(得分:0)
"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'
答案 2 :(得分:0)
1)nready
的{{1}}字段用于确定准备使用的任务数,即数组struct nready
中的剩余任务。 buff
语句仅在生产者在数组nready.nready++;
中放置一个新项时执行,而buff
仅在消费从nready.nready--;
中获取项目时执行。如果是变量,程序员总是可以跟踪剩余的任务数量。
2)
buff
上述陈述是常见的条件变量用法。你可以检查一下 POSIX Threads Programming和Condition Variables了解有关条件变量的更多信息。
为什么不能只使用互斥?您可以反复轮询互斥锁。显然,它耗费CPU时间,可能会对系统性能产生巨大影响。相反,当pthread_mutex_lock(&nready.mutex);
while (nready.nready == 0)
pthread_cond_wait(&nready.cond, &nready.mutex);
nready.nready--;
pthread_mutex_unlock(&nready.mutex);
中没有更多项目时,您希望消费在睡眠中等待,并且当生产者将新项目放入buff
时唤醒消费。条件变量在此处充当此角色。当没有项目(nready.nready == 0)时,buff
函数将当前线程置于休眠状态,节省宝贵的cpu时间。当新物品到达时,pthread_cond_wait()
会唤醒消费者。