微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C 中的线程安全队列出现分段错误

如何解决C 中的线程安全队列出现分段错误

我是 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,即使 NULLQ->head 时它应该是 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 有一个带演示的工作线程安全队列实现。 (不过,它使用固定大小的循环缓冲区而不是链表。)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。