互斥线程 - 代码似乎没有正确退出
Mutex Threading - Code doesn't seem to Exit Properly
所以我这里有创建两种线程的代码。一种 "produces" 数据,另一种 "consumes" 数据。任何时候只能存在一定数量的数据,所以一旦创建了一定数量的数据(即sharedData = BUFFER时),生产者就会暂停生产,而当sharedData = 0时,消费者会暂停. 也只能制作这么多数据(dataleft中存储的数量),一旦制作和消费完所有数据,程序就应该结束了。
出于某种原因,我在代码末尾的 printf() 行似乎从未触发过。因此,我无法判断线程是否正确关闭。感觉自己做了一件很蠢的事,但是看不出问题所在
开头的几个定义:
#define NUMCONSUMERS 4
#define NUMPRODUCERS 4
#define PACKETS 10
#define tryMainlock pthread_mutex_trylock(&dataMutex)
#define openMainlock pthread_mutex_lock(&dataMutex)
#define closeMainlock pthread_mutex_unlock(&dataMutex)
#define waitMainlock pthread_cond_wait(&dataPresentCondition, &dataMutex);
#define signalMainlock pthread_cond_signal(&dataPresentCondition);
#define trydatalock pthread_mutex_trylock(&IsthereDataleft)
#define opendatalock pthread_mutex_lock(&IsthereDataleft)
#define closedatalock pthread_mutex_unlock(&IsthereDataleft)
pthread_mutex_t dataMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t dataPresentCondition = PTHREAD_COND_INITIALIZER;
pthread_mutex_t IsthereDataleft = PTHREAD_MUTEX_INITIALIZER;
int sharedData=0; //amount of data present
int BUFFER = 5;
int dataleft=PACKETS;
主要功能:
int main(int argc, char **argv)
{
int rc;
int i;
pthread_t consumer[NUMCONSUMERS];
pthread_t producer[NUMPRODUCERS];
rc = opendatalock; //lock to determine whether there's any point waiting for data
for (i=0; i <NUMPRODUCERS; i++) { //Build up the producers
rc = pthread_create(&producer[i], NULL, Producer, (void *)i);
if (rc)
printf("Error building Producer Thread: %x\n", i);
}
for (i=0; i <NUMCONSUMERS; i++) { //Build up the consumers
rc = pthread_create(&consumer[i], NULL, Consumer, (void *)i);
if (rc)
printf("Error building Consumer Thread: %x\n", i);
}
printf("All Producers and Consumers created\n");
for (i=0; i <NUMPRODUCERS; i++) { //Join up the producers
rc = pthread_join(producer[i], NULL);
if (rc)
printf("Error: Producer %x: Failed to join\n", i);
}
rc = closedatalock; //producers finished, no data left to make
printf("datalock closed, consumers finishing...\n");
for (i=0; i <NUMCONSUMERS; i++) { //Join up the consumers
rc = pthread_join(consumer[i], NULL);
if (rc)
printf("Error: Consumer %x: Failed to join\n", i);
}
rc = pthread_mutex_destroy(&dataMutex);
rc = pthread_cond_destroy(&dataPresentCondition);
rc = pthread_mutex_destroy(&IsthereDataleft);
printf("All Threads finished. Exiting....\n");
return 0;
}
消费者线程:
void *Consumer(void *threadid){
int rc;
printf("Consumer Thread %x: Created\n", (int)threadid);
while (1)
{
printf("Consumer %x: Entering Loop\n", (int)threadid);
rc = openMainlock; //take hold of main lock
if (rc)
{
printf("Consumer %x: Waiting...\n", (int)threadid);
rc = waitMainlock; //if main lock is taken, wait
if (rc) //if wait fails, exit the thread.
{
printf("Consumer Thread %x: wait for Main Lock failed\n", threadid);
exit(0);
}
}
while (sharedData == 0) //if the buffer is empty
{
rc = trydatalock;
if (!rc)
{
printf("Consumer %x: Completed. Exiting...\n");
exit(0);
}
rc = closeMainlock;
if (rc)
{
printf("code.\n");
}
rc = waitMainlock;
if (rc)
{
printf("code.\n");
}
}
sharedData--;
rc = closeMainlock;
rc = signalMainlock;
if (rc)
{
printf("code.\n");
}
printf("Consumer %x: Releasing Lock\n", (int)threadid);
}
}
生产者线程:
void *Producer(void *threadid){
int rc;
printf("Producer Thread %x: Created\n", (int)threadid);
while (1)
{
printf("Producer %x: Entering Loop\n", (int)threadid);
rc = openMainlock; //take hold of the lock
if (rc) //if lock is currently being used by a consumer or a producer
{
printf("Producer %x: Waiting...\n", (int)threadid);
rc = waitMainlock; //wait here until lock is released
if (rc)
{
printf("Producer Thread %x: wait for Main Lock failed\n", threadid);
exit(0);
}
}
if (!dataleft) //If there's no data left to add to the stream, close the thread
{
printf("Producer Thread %x: Completed, exiting...\n", (int)threadid);
exit(0);
}
while (sharedData >=BUFFER)
{
rc = closeMainlock;
if (rc)
{
printf("code.\n");
}
rc = waitMainlock;
if (rc)
{
printf("code.\n");
}
}
printf("Producer %x: Lock Acquired\n", (int)threadid);
sharedData++;
dataleft--;
rc = closeMainlock;
rc = signalMainlock;
if (rc)
{
printf("code.\n");
}
printf("Producer %x: Releasing Lock\n", (int)threadid);
}
}
您对 openMainlock
的使用似乎有问题,它扩展为 pthread_mutex_lock
调用。
一方面,你不应该期望从 openMainlock
得到一个非零的 return 值:pthread_mutex_lock
应该 return 零(获得锁) 或块,除非互斥锁未初始化或者是错误检查互斥锁。
此外,一旦获得锁,如果生产者完成,即dataleft
为零,线程调用exit(0)
,这将终止整个进程而不是终止线程。 pthread_exit
应该改用,或者只是函数中的 return,但请注意,此时您仍然拥有主锁,它不会被释放。
查看这段代码:
if (!rc)
{
printf("Consumer %x: Completed. Exiting...\n");
exit(0);
}
如果消费者已经完成,则进程(!)终止。您需要使用 pthread_exit() 代替,或者只是使用线程函数中的 return。
那么,还有
../nptl/pthread_mutex_lock.c:80:
__pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed.
其中我得到了几次运行的代码。这可能是由例如双重解锁或其他一些无效使用。我将从清理奇怪的宏开始,以便您可以自由查看程序本身的逻辑。
此外,关于互斥量的一个重要建议:始终准确记录哪些数据应受互斥量保护。关键是它并不总是很清楚,弄错意味着您不小心访问了没有同步的数据。为了使这一点非常清楚,请使用如下结构:
struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
int data;
} synced_data = {
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_COND_INITIALIZER,
0
};
实际上,文档的重要性不仅仅在于共享数据。考虑例如 IsthereDataleft
:这是一个互斥体,但它不保护任何东西,对吗?相反,它用于向启动的线程发出信号,表明没有什么可做的,对吧?记录下来不仅可以帮助其他人理解您的代码,而且可以确保您了解自己的意图。有时,在尝试解释它时,您会发现自己有些事情没有意义。
所以我这里有创建两种线程的代码。一种 "produces" 数据,另一种 "consumes" 数据。任何时候只能存在一定数量的数据,所以一旦创建了一定数量的数据(即sharedData = BUFFER时),生产者就会暂停生产,而当sharedData = 0时,消费者会暂停. 也只能制作这么多数据(dataleft中存储的数量),一旦制作和消费完所有数据,程序就应该结束了。
出于某种原因,我在代码末尾的 printf() 行似乎从未触发过。因此,我无法判断线程是否正确关闭。感觉自己做了一件很蠢的事,但是看不出问题所在
开头的几个定义:
#define NUMCONSUMERS 4
#define NUMPRODUCERS 4
#define PACKETS 10
#define tryMainlock pthread_mutex_trylock(&dataMutex)
#define openMainlock pthread_mutex_lock(&dataMutex)
#define closeMainlock pthread_mutex_unlock(&dataMutex)
#define waitMainlock pthread_cond_wait(&dataPresentCondition, &dataMutex);
#define signalMainlock pthread_cond_signal(&dataPresentCondition);
#define trydatalock pthread_mutex_trylock(&IsthereDataleft)
#define opendatalock pthread_mutex_lock(&IsthereDataleft)
#define closedatalock pthread_mutex_unlock(&IsthereDataleft)
pthread_mutex_t dataMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t dataPresentCondition = PTHREAD_COND_INITIALIZER;
pthread_mutex_t IsthereDataleft = PTHREAD_MUTEX_INITIALIZER;
int sharedData=0; //amount of data present
int BUFFER = 5;
int dataleft=PACKETS;
主要功能:
int main(int argc, char **argv)
{
int rc;
int i;
pthread_t consumer[NUMCONSUMERS];
pthread_t producer[NUMPRODUCERS];
rc = opendatalock; //lock to determine whether there's any point waiting for data
for (i=0; i <NUMPRODUCERS; i++) { //Build up the producers
rc = pthread_create(&producer[i], NULL, Producer, (void *)i);
if (rc)
printf("Error building Producer Thread: %x\n", i);
}
for (i=0; i <NUMCONSUMERS; i++) { //Build up the consumers
rc = pthread_create(&consumer[i], NULL, Consumer, (void *)i);
if (rc)
printf("Error building Consumer Thread: %x\n", i);
}
printf("All Producers and Consumers created\n");
for (i=0; i <NUMPRODUCERS; i++) { //Join up the producers
rc = pthread_join(producer[i], NULL);
if (rc)
printf("Error: Producer %x: Failed to join\n", i);
}
rc = closedatalock; //producers finished, no data left to make
printf("datalock closed, consumers finishing...\n");
for (i=0; i <NUMCONSUMERS; i++) { //Join up the consumers
rc = pthread_join(consumer[i], NULL);
if (rc)
printf("Error: Consumer %x: Failed to join\n", i);
}
rc = pthread_mutex_destroy(&dataMutex);
rc = pthread_cond_destroy(&dataPresentCondition);
rc = pthread_mutex_destroy(&IsthereDataleft);
printf("All Threads finished. Exiting....\n");
return 0;
}
消费者线程:
void *Consumer(void *threadid){
int rc;
printf("Consumer Thread %x: Created\n", (int)threadid);
while (1)
{
printf("Consumer %x: Entering Loop\n", (int)threadid);
rc = openMainlock; //take hold of main lock
if (rc)
{
printf("Consumer %x: Waiting...\n", (int)threadid);
rc = waitMainlock; //if main lock is taken, wait
if (rc) //if wait fails, exit the thread.
{
printf("Consumer Thread %x: wait for Main Lock failed\n", threadid);
exit(0);
}
}
while (sharedData == 0) //if the buffer is empty
{
rc = trydatalock;
if (!rc)
{
printf("Consumer %x: Completed. Exiting...\n");
exit(0);
}
rc = closeMainlock;
if (rc)
{
printf("code.\n");
}
rc = waitMainlock;
if (rc)
{
printf("code.\n");
}
}
sharedData--;
rc = closeMainlock;
rc = signalMainlock;
if (rc)
{
printf("code.\n");
}
printf("Consumer %x: Releasing Lock\n", (int)threadid);
}
}
生产者线程:
void *Producer(void *threadid){
int rc;
printf("Producer Thread %x: Created\n", (int)threadid);
while (1)
{
printf("Producer %x: Entering Loop\n", (int)threadid);
rc = openMainlock; //take hold of the lock
if (rc) //if lock is currently being used by a consumer or a producer
{
printf("Producer %x: Waiting...\n", (int)threadid);
rc = waitMainlock; //wait here until lock is released
if (rc)
{
printf("Producer Thread %x: wait for Main Lock failed\n", threadid);
exit(0);
}
}
if (!dataleft) //If there's no data left to add to the stream, close the thread
{
printf("Producer Thread %x: Completed, exiting...\n", (int)threadid);
exit(0);
}
while (sharedData >=BUFFER)
{
rc = closeMainlock;
if (rc)
{
printf("code.\n");
}
rc = waitMainlock;
if (rc)
{
printf("code.\n");
}
}
printf("Producer %x: Lock Acquired\n", (int)threadid);
sharedData++;
dataleft--;
rc = closeMainlock;
rc = signalMainlock;
if (rc)
{
printf("code.\n");
}
printf("Producer %x: Releasing Lock\n", (int)threadid);
}
}
您对 openMainlock
的使用似乎有问题,它扩展为 pthread_mutex_lock
调用。
一方面,你不应该期望从 openMainlock
得到一个非零的 return 值:pthread_mutex_lock
应该 return 零(获得锁) 或块,除非互斥锁未初始化或者是错误检查互斥锁。
此外,一旦获得锁,如果生产者完成,即dataleft
为零,线程调用exit(0)
,这将终止整个进程而不是终止线程。 pthread_exit
应该改用,或者只是函数中的 return,但请注意,此时您仍然拥有主锁,它不会被释放。
查看这段代码:
if (!rc)
{
printf("Consumer %x: Completed. Exiting...\n");
exit(0);
}
如果消费者已经完成,则进程(!)终止。您需要使用 pthread_exit() 代替,或者只是使用线程函数中的 return。
那么,还有
../nptl/pthread_mutex_lock.c:80:
__pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed.
其中我得到了几次运行的代码。这可能是由例如双重解锁或其他一些无效使用。我将从清理奇怪的宏开始,以便您可以自由查看程序本身的逻辑。
此外,关于互斥量的一个重要建议:始终准确记录哪些数据应受互斥量保护。关键是它并不总是很清楚,弄错意味着您不小心访问了没有同步的数据。为了使这一点非常清楚,请使用如下结构:
struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
int data;
} synced_data = {
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_COND_INITIALIZER,
0
};
实际上,文档的重要性不仅仅在于共享数据。考虑例如 IsthereDataleft
:这是一个互斥体,但它不保护任何东西,对吗?相反,它用于向启动的线程发出信号,表明没有什么可做的,对吧?记录下来不仅可以帮助其他人理解您的代码,而且可以确保您了解自己的意图。有时,在尝试解释它时,您会发现自己有些事情没有意义。