C 中的线程安全队列出现分段错误
Threadsafe Queue in C getting Segmentation Fault
我是 C 的新手,对多线程和尝试创建线程安全队列数据结构甚至是新手。它在 dequeue() 的第 116 行出现段错误(在代码中注释),我想知道是否有人可以看到我的实现有任何明显的问题。非常感谢
typedef struct node{
char *data;
struct node *next;
} node;
extern int directoryThreads;
//unbounded queue for file and directory queue
typedef struct {
node *head;;
node *tail;
int activeThreads;
int open;
int count;
pthread_mutex_t lock;
pthread_cond_t read_ready;
//pthread_cond_t write_ready;
} queue_t;
char *dequeue(queue_t *Q)
{
pthread_mutex_lock(&Q->lock); //lock queue
if(isempty(Q)){
Q->activeThreads--;
if(Q->activeThreads == 0){
pthread_mutex_unlock(&Q->lock);
return NULL;
}
while (isempty(Q) && Q->activeThreads>0) {
pthread_cond_wait(&Q->read_ready, &Q->lock);
}
if (isempty(Q)){
pthread_mutex_unlock(&Q->lock);
return NULL;
}
Q->activeThreads++;
}
//printf("%s", "Dequeued: ");
//display(Q->head);
char *item = (char *) malloc(strlen(Q->head->data) + 1); //segault here
item = Q->head->data;
if(Q->count>1){
Q->head = Q->head->next;
}
else{
Q->head = NULL;
}
Q->count--;
pthread_mutex_unlock(&Q->lock);
return item;
}
问题出在别处。 (我不排除导致竞争条件的信令协议问题,但我对此表示怀疑。稍后会详细介绍。)
如果信号是由 Q->head->data
发出的,Q->head
包含垃圾,或者 isempty(Q)
和 Q->head != NULL
不一致。
如果信号由 strlen
抛出,Q->head->data
包含垃圾,或者字符串未正确以 NUL 结尾。
这并不意味着 dequeue
.
没有问题
- 你在
dequeue
中无故分配了内存。
- 更糟糕的是,您在下一行覆盖了
malloc
返回的指针,导致内存泄漏。
dequeue
永远不会改变 Q->tail
,即使当 Q->head
是 NULL
. 时它应该是 NULL
- 信令协议过于复杂。
固定:
// Call done() when nothing will be added to the queue anymore.
// This is done to unblock calls to dequeue, and
// to the cause future calls to return immediately.
void Queue_done(queue_t *Q) {
pthread_mutex_lock(&Q->lock);
Q->done = 1;
// In case another thread is blocked in dequeue().
pthread_cond_signal(&Q->read_ready);
pthread_mutex_unlock(&Q->lock);
}
char *Queue_dequeue(queue_t *Q) {
pthread_mutex_lock(&Q->lock);
while (!Q->head && !Q->done)
pthread_cond_wait(&Q->read_ready, &Q->lock);
char *rv;
if (Q->head) {
rv = Q->head->data;
Q->head = Q->head->next;
if (!Q->head)
Q->tail = NULL;
--Q->count;
} else {
// done() was called and queue is empty.
rv = NULL;
}
// In case another thread is blocked in dequeue().
pthread_cond_signal(&Q->read_ready);
pthread_mutex_unlock(&Q->lock);
return rv;
}
示例程序:
static queue_t Q;
void consumer(void) {
while (1) {
char *job = Queue_dequeue(&Q);
if (!job)
break;
// Do something with `job`.
free(job);
}
}
int main(void) {
Queue_init(&Q);
// Creates consumer threads here.
// Add stuff to queue here.
// -or-
// Create producer threads wait for them to complete here.
Queue_done(&Q);
// Wait for consumer threads to complete here.
Queue_destroy(&Q);
}
我之前有 posted 一个工作的线程安全队列实现和演示。 (不过,它使用固定大小的循环缓冲区而不是链表。)
我是 C 的新手,对多线程和尝试创建线程安全队列数据结构甚至是新手。它在 dequeue() 的第 116 行出现段错误(在代码中注释),我想知道是否有人可以看到我的实现有任何明显的问题。非常感谢
typedef struct node{
char *data;
struct node *next;
} node;
extern int directoryThreads;
//unbounded queue for file and directory queue
typedef struct {
node *head;;
node *tail;
int activeThreads;
int open;
int count;
pthread_mutex_t lock;
pthread_cond_t read_ready;
//pthread_cond_t write_ready;
} queue_t;
char *dequeue(queue_t *Q)
{
pthread_mutex_lock(&Q->lock); //lock queue
if(isempty(Q)){
Q->activeThreads--;
if(Q->activeThreads == 0){
pthread_mutex_unlock(&Q->lock);
return NULL;
}
while (isempty(Q) && Q->activeThreads>0) {
pthread_cond_wait(&Q->read_ready, &Q->lock);
}
if (isempty(Q)){
pthread_mutex_unlock(&Q->lock);
return NULL;
}
Q->activeThreads++;
}
//printf("%s", "Dequeued: ");
//display(Q->head);
char *item = (char *) malloc(strlen(Q->head->data) + 1); //segault here
item = Q->head->data;
if(Q->count>1){
Q->head = Q->head->next;
}
else{
Q->head = NULL;
}
Q->count--;
pthread_mutex_unlock(&Q->lock);
return item;
}
问题出在别处。 (我不排除导致竞争条件的信令协议问题,但我对此表示怀疑。稍后会详细介绍。)
如果信号是由 Q->head->data
发出的,Q->head
包含垃圾,或者 isempty(Q)
和 Q->head != NULL
不一致。
如果信号由 strlen
抛出,Q->head->data
包含垃圾,或者字符串未正确以 NUL 结尾。
这并不意味着 dequeue
.
- 你在
dequeue
中无故分配了内存。 - 更糟糕的是,您在下一行覆盖了
malloc
返回的指针,导致内存泄漏。 dequeue
永远不会改变Q->tail
,即使当Q->head
是NULL
. 时它应该是 - 信令协议过于复杂。
NULL
固定:
// Call done() when nothing will be added to the queue anymore.
// This is done to unblock calls to dequeue, and
// to the cause future calls to return immediately.
void Queue_done(queue_t *Q) {
pthread_mutex_lock(&Q->lock);
Q->done = 1;
// In case another thread is blocked in dequeue().
pthread_cond_signal(&Q->read_ready);
pthread_mutex_unlock(&Q->lock);
}
char *Queue_dequeue(queue_t *Q) {
pthread_mutex_lock(&Q->lock);
while (!Q->head && !Q->done)
pthread_cond_wait(&Q->read_ready, &Q->lock);
char *rv;
if (Q->head) {
rv = Q->head->data;
Q->head = Q->head->next;
if (!Q->head)
Q->tail = NULL;
--Q->count;
} else {
// done() was called and queue is empty.
rv = NULL;
}
// In case another thread is blocked in dequeue().
pthread_cond_signal(&Q->read_ready);
pthread_mutex_unlock(&Q->lock);
return rv;
}
示例程序:
static queue_t Q;
void consumer(void) {
while (1) {
char *job = Queue_dequeue(&Q);
if (!job)
break;
// Do something with `job`.
free(job);
}
}
int main(void) {
Queue_init(&Q);
// Creates consumer threads here.
// Add stuff to queue here.
// -or-
// Create producer threads wait for them to complete here.
Queue_done(&Q);
// Wait for consumer threads to complete here.
Queue_destroy(&Q);
}
我之前有 posted 一个工作的线程安全队列实现和演示。 (不过,它使用固定大小的循环缓冲区而不是链表。)