2009-02-24 50 views
4

嘿,大家好。我一直在研究一些代碼,以便在需要時產生線程,但是決定一個更簡單和更有效的解決方案是創建一個線程池。它使用我有條件等待排隊和出隊的隊列來實現。我發佈這個的唯一原因是因爲我在我的代碼中隨機地得到了一些奇怪的錯誤,這些錯誤是在切換到線程池之前從未發生過的,當我添加了一些調試打印語句時,這些錯誤消失了。如果我的代碼因爲打印語句而開始工作,這聽起來像是內存問題,堆棧可能由一些不好的線程代碼引起。ThreadPool最佳實踐,正確性

我覺得首先要看看線程池中的正確性和線程安全性。這是3個主要功能。 Threadstart是每個線程等待出隊的函數,以及產生線程的init函數。最後一個是排隊工作項目。 q_enq函數將喚醒某些線程然後出列的條件變量。

void * 
threadstart(void *arg) 
{ 
    threadpool_t * tp = (threadpool_t*)arg; 

    while (1) 
    { 
     workitem_t *work = q_dq(tp->workqueue); 

     if (work == NULL) 
      break; 

     (*work->action)(work->arg); 
     free(work); 
    } 

    pthread_exit(NULL); 
}; 

threadpool_t * 
threadpool_init(int max_threads, int max_workload) 
{ 
    threadpool_t *tp; 
    pthread_attr_t attr; 
    register int i=0; 
    int rc =0; 
    ASSERT(max_threads > 0 && max_workload > 0); 

    tp = malloc(sizeof(threadpool_t)); 
    tp->max_threads = max_threads; 
    tp->threads = calloc(max_threads, sizeof(pthread_t)); 
    tp->workqueue = q_init(max_workload); 

    pthread_attr_init(&attr); 
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 
    pthread_attr_setschedpolicy(&attr, SCHED_RR); 

    for (; i < max_threads; i++) 
    { 
     rc = pthread_create(&tp->threads[i], &attr, threadstart, tp); 

     /* worry about errors creating threads later :(*/ 
     if (rc) printf("Error creating threadpool thread %d [%d]\r\n", i, rc); 
    } 
    pthread_attr_destroy(&attr); 

    return tp; 
} 
void 
threadpool_q_workitem(threadpool_t *tp, action_f action, void *arg) 
{ 
    workitem_t *item; 
    ASSERT(tp != NULL); 

    item = malloc(sizeof(workitem_t)); 
    item->action = action; 
    item->arg = arg; 
    q_enq(tp->workqueue, (void*)item); 
}; 

編輯:隊列功能

void q_enq(struct queue *q, void *data) { 
    struct timeval now; 
    struct timespec timeout; 

    pthread_mutex_lock(q->mut); 

    while (q->full) { 
     gettimeofday(&now, (struct timezone *)0); 
     timeout.tv_sec = now.tv_sec + Q_TIMEOUT; 
     timeout.tv_nsec = now.tv_usec * 1000; 

     pthread_cond_timedwait(q->notfull, q->mut, &timeout); 

    } 
    q->buffer[q->tail++] = data; 
    if (q->tail == q->num) { 
     q->tail = 0; 
    } 
    if (q->head == q->tail) { 
     q->full = 1; 
    } 
    q->empty = 0; 

    pthread_mutex_unlock(q->mut); 
    pthread_cond_signal(q->notempty); 
} 

void *q_dq(struct queue *q) { 
    void *data; 
    int rc; 
    struct timeval now; 
    struct timespec timeout; 

    pthread_mutex_lock(q->mut); 

    while (q->empty) { 
     gettimeofday(&now, NULL); 
     timeout.tv_sec = now.tv_sec + Q_TIMEOUT; 
     timeout.tv_nsec = now.tv_usec * 1000; 
     if (q->finished) { 
      pthread_mutex_unlock(q->mut); 
      return NULL; 
     } 

     rc = pthread_cond_timedwait(q->notempty, q->mut, &timeout); 
     if (q->finished) { 
      pthread_mutex_unlock(q->mut); 
      return NULL; 
     } 
    } 
    data = q->buffer[q->head++]; 
    if (q->head == q->num) { 
     q->head = 0; 
    } 
    if (q->head == q->tail) { 
     q->empty = 1; 
    } 
    q->full = 0; 
    pthread_mutex_unlock(q->mut); 
    pthread_cond_signal(q->notfull); 

    return data; 
} 
+0

請注意q_enq和q_dq函數,因爲它必須具有鎖定功能。哪一個是最可能的問題。 – sfossen 2009-02-24 15:28:27

回答

6

我認爲你應該做這樣的事情:

void q_enq(struct queue *q, void *data) { 
    int next; 

    // wait until there's room 
    do{ 
     pthread_mutex_lock(q->mut); 

     next = q->tail + 1; 
     if(next == q->num) { 
      next = 0; 
     } 

     // still room to add 
     if(q->head != next) 
      break; 

     pthread_mutex_unlock(q->mut); 
     sched_yield(); 
    } while(1); 

    q->tail = next; 
    q->buffer[ q->tail ] = data; 

    // signal consumer and unlock mutex 
    pthread_cond_signal(q->notempty); 
    pthread_mutex_unlock(q->mut); 
} 

void *q_dq(struct queue *q) { 
    void *data; 
    int rc; 

    pthread_mutex_lock(q->mut); 

    // while empty wait 
    while(q->tail == q->head){ 
     pthread_cond_wait(q->notempty, q->mut); 
    } 

    // get next and wrap 
    data = q->buffer[q->head++]; 
    if (q->head == q->num) { 
     q->head = 0; 
    } 

    pthread_mutex_unlock(q->mut); 
    return data; 
} 
+0

今天晚些時候我會試試看。我正在運行一些東西,沒有時間重建... – 2009-02-24 16:27:49

+0

你有機會嘗試它嗎?還沒有 – sfossen 2009-02-25 21:47:04

1

你打電話pthread_attr_destroy太早;請不要致電pthread_attr_destroy,直到其銷燬池(即保持線程的使用壽命)