【问题标题】:Threadsafe Queue in C getting Segmentation FaultC中的线程安全队列出现分段错误
【发布时间】:2021-04-16 04:01:42
【问题描述】:

我是 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;
}

【问题讨论】:

    标签: c multithreading data-structures queue


    【解决方案1】:

    问题出在其他地方。 (我不排除导致竞争条件的信号协议问题,但我对此表示怀疑。稍后会详细介绍。)

    如果信号由Q->head->data抛出,Q->head包含垃圾,或者isempty(Q)Q->head != NULL不一致。

    如果信号由strlen 抛出,Q->head->data 包含垃圾,或者字符串未正确以 NUL 终止。


    这并不意味着dequeue 没有问题。

    • 你无缘无故地在dequeue分配内存。
    • 更糟糕的是,您在下一行覆盖了malloc 返回的指针,导致内存泄漏。
    • dequeue 永远不会改变 Q->tail,即使当 Q->headNULL 时它应该是 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 有一个工作线程安全队列实现,带有演示。 (不过,它使用固定大小的循环缓冲区而不是链表。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-13
      • 2012-11-05
      • 2023-03-04
      • 2013-02-23
      • 2017-06-14
      • 1970-01-01
      • 2010-11-15
      • 1970-01-01
      相关资源
      最近更新 更多