我正在尝试使用此代码,但由于某种原因,它会在30秒内死锁。
死锁似乎发生了Putting或Getting,缓冲区是否已满。
我错过了一些明显或不使用的东西吗?我是C的新手!
编译:gcc -Wall -o test test.c -lpthread
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
struct sequence {
pthread_mutex_t mutex;
int count;
};
struct event {
pthread_mutex_t critical;
pthread_mutex_t critical2;
pthread_mutex_t signalM;
pthread_cond_t signalC;
int eventCount;
};
struct allVars {
struct sequence putSeq;
struct sequence getSeq;
struct event inEvents;
struct event outEvents;
int bufferSize;
char buffer[10][128];
};
/**
* Issue tickets in sequence. Used in conjunction with an Event Counter
*/
int getTicket(struct sequence *seq) {
// begin critical section
if (pthread_mutex_lock(&seq->mutex) != 0) {
printf("mutex_lock in getticket error\n");
}
// remember current count
int oldCount = seq->count;
// increment count
seq->count++;
// end critical section
if (pthread_mutex_unlock(&seq->mutex) != 0) {
printf("mutex_unlock in getticket error\n");
}
return oldCount;
}
/**
* Advance the EventCount (ticket)
*/
void advance(struct event *event) {
// begin critical section
if (pthread_mutex_lock(&event->critical) != 0) {
fprintf(stderr, "mutex_lock in advance error\n");
exit(EXIT_FAILURE);
}
// increment the event counter
event->eventCount++;
// end critical section
if (pthread_mutex_unlock(&event->critical) != 0) {
fprintf(stderr, "mutex_unlock in advance error\n");
exit(EXIT_FAILURE);
}
// signal await to continue
if (pthread_cond_signal(&event->signalC) != 0) {
fprintf(stderr, "cond_signal in advance error\n");
exit(EXIT_FAILURE);
}
}
/**
* Wait for ticket and buffer availability
*/
void await(struct event *event, int ticket) {
int eventCount;
// begin critical section
if (pthread_mutex_lock(&event->critical) != 0) {
fprintf(stderr, "mutex_lock in advance error\n");
exit(EXIT_FAILURE);
}
eventCount = event->eventCount;
// end critical section
if (pthread_mutex_unlock(&event->critical) != 0) {
fprintf(stderr, "mutex_unlock in advance error\n");
exit(EXIT_FAILURE);
}
// loop until the ticket machine shows your number
while (ticket > eventCount) {
// wait until a ticket is called
pthread_cond_wait(&event->signalC, &event->signalM);
// begin critical section
if (pthread_mutex_lock(&event->critical) != 0) {
fprintf(stderr, "mutex_lock in advance error\n");
exit(EXIT_FAILURE);
}
eventCount = event->eventCount;
// end critical section
if (pthread_mutex_unlock(&event->critical) != 0) {
fprintf(stderr, "mutex_unlock in advance error\n");
exit(EXIT_FAILURE);
}
}
}
/**
* Add to buffer
*/
void putBuffer(struct allVars *allVars, char data[]) {
// get a ticket
int ticket = getTicket(&allVars->putSeq);
// get the current write position
int in;
// begin critical section
if (pthread_mutex_lock(&allVars->inEvents.critical) != 0) {
fprintf(stderr, "mutex_lock in put error\n");
exit(EXIT_FAILURE);
}
in = allVars->inEvents.eventCount;
// end critical section
if (pthread_mutex_unlock(&allVars->inEvents.critical) != 0) {
fprintf(stderr, "mutex_unlock in put error\n");
exit(EXIT_FAILURE);
}
// wait for ticket to be called (sequential writing)
await(&allVars->inEvents, ticket);
// wait until theres a space free in the buffer
await(&allVars->outEvents, in - allVars->bufferSize + 1); // set to 2 to keep 1 index distance
// begin critical section
if (pthread_mutex_lock(&allVars->inEvents.critical2) != 0) {
fprintf(stderr, "mutex_lock in put error\n");
exit(EXIT_FAILURE);
}
// add data to buffer
strcpy(allVars->buffer[ticket % allVars->bufferSize], data);
// end critical section
if (pthread_mutex_unlock(&allVars->inEvents.critical2) != 0) {
fprintf(stderr, "mutex_unlock in put error\n");
exit(EXIT_FAILURE);
}
// increment the ticket display
advance(&allVars->inEvents);
}
/**
* Get from buffer
*/
char *getBuffer(struct allVars *allVars) {
// get a ticket
int ticket = getTicket(&allVars->getSeq);
// get the current read position
int out;
// begin critical section
if (pthread_mutex_lock(&allVars->outEvents.critical) != 0) {
fprintf(stderr, "mutex_lock in get error\n");
exit(EXIT_FAILURE);
}
out = allVars->outEvents.eventCount;
// end critical section
if (pthread_mutex_unlock(&allVars->outEvents.critical) != 0) {
fprintf(stderr, "mutex_unlock in get error\n");
exit(EXIT_FAILURE);
}
// wait for ticket to be called (sequential reading)
await(&allVars->outEvents, ticket);
// wait until theres something in the buffer
await(&allVars->inEvents, out + 1);
char *str = malloc(128);
// critical section
if (pthread_mutex_lock(&allVars->inEvents.critical2) != 0) {
fprintf(stderr, "mutex_lock in put error\n");
exit(EXIT_FAILURE);
}
// get the buffer data
strcpy(str, allVars->buffer[ticket % allVars->bufferSize]);
// end critical section
if (pthread_mutex_unlock(&allVars->inEvents.critical2) != 0) {
fprintf(stderr, "mutex_unlock in put error\n");
exit(EXIT_FAILURE);
}
// increment buffer availability
advance(&allVars->outEvents);
return str;
}
/** child thread (producer) */
void *childThread(void *allVars) {
char str[10];
int count = 0;
while (true) {
sprintf(str, "%d", count++);
putBuffer(allVars, str);
}
pthread_exit(EXIT_SUCCESS);
}
int main(void) {
// init structs
struct sequence putSeq = {
PTHREAD_MUTEX_INITIALIZER,
0
};
struct sequence getSeq = {
PTHREAD_MUTEX_INITIALIZER,
0
};
struct event inEvents = {
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_COND_INITIALIZER,
0
};
struct event outEvents = {
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_COND_INITIALIZER,
0
};
struct allVars allVars = {
putSeq, // sequence
getSeq,
inEvents, // events
outEvents,
10, // buffersize
{"", {""}} // buffer[][]
};
pthread_mutex_lock(&allVars.inEvents.signalM);
pthread_mutex_lock(&allVars.outEvents.signalM);
// create child thread (producer)
pthread_t thread;
if (pthread_create(&thread, NULL, childThread, &allVars)) {
fprintf(stderr, "failed to create child thread");
exit(EXIT_FAILURE);
}
// (consumer)
while (true) {
char *out = getBuffer(&allVars);
printf("buf: %s\n", out);
free(out);
}
return (EXIT_SUCCESS);
}
答案 0 :(得分:1)
我不确定这是否是您的问题的根源,但这是一个肯定会导致锁定问题的错误:
您使用pthread_cond_wait
和pthread_cond_signal
错误。在调用pthread_cond_wait
或pthread_cond_signal
之前,您应始终锁定条件的互斥锁。
pthread_cond_wait
会自动为您释放互斥锁,并在信号后重新获取互斥锁。因此,您必须在发出线程信号后释放锁定。
This pthread programming tutorial给了我很多帮助。我建议看看它,因为它还涵盖了pthread编程的其他一些方面(例如互斥)。