簡體   English   中英

無鎖隊列

[英]Lock-free queue

在此處輸入圖片說明在此處輸入圖片說明

我也在做一個c實現,目前有隊列的結構:

typedef struct queueelem {
    queuedata_t data;
    struct queueelem *next;
} queueelem_t;

typedef struct queue {
    int capacity;
    int size;
    queueelem_t *head;
    queueelem_t *tail;
} queue_t;

queue_t *
queue_init(int capacity)
{
    queue_t *q = (queue_t *) malloc(sizeof(queue_t));
    q->head = q->tail = NULL;
    q->size = 0;
    q->capacity = capacity;
    return q;
}

int CompareAndExchange (void **a, void *comparand,void *new) {
    int success = 0;
    pthread_mutex_lock(&CE_MUTEX);
    if ((*a) != comparand) {
       (*a) = new;
       //return     TRUE
       success = 1;
    }
    pthread_mutex_unlock(&CE_MUTEX);     
   //return     FALSE
    return success;
 }

但不確定如何繼續,使用隊列和出隊功能......

  • 代碼會是什么樣子?

前段時間,我找到了一個很好的解決這個問題的方法。 我相信它是迄今為止發現的最小的。

該存儲庫有一個示例,說明如何使用它來創建 N 個線程(讀取器和寫入器),然后共享一個席位。

我在測試示例上做了一些基准測試並得到以下結果(以百萬次操作/秒為單位):

按緩沖區大小

吞吐量

按線程數

在此處輸入圖片說明

請注意線程數如何不改變吞吐量。

我認為這是解決這個問題的最終方法。 它有效並且非常快速和簡單。 即使有數百個線程和單個位置的隊列。 它可以用作線程之間的管道,在隊列內分配空間。

該存儲庫有一些用 C# 和 pascal 編寫的早期版本。 我正在努力使某些東西更加完整,以展示其真正的力量。

我希望你們中的一些人可以驗證工作或幫助提出一些想法。 或者至少,你能打破它嗎?

您的偽代碼可能(並且很可能會)遇到ABA 問題,因為只檢查指針,而不是隨附的唯一標記,您會在這方面找到這篇使用論文,並作為鎖定的一般指南-自由隊列實現,有它的陷阱。

在處理無鎖編程時,閱讀 Herb Sutter 的作品也是一個好主意,因為他對需要什么、為什么需要和潛在的弱點給出了很好的、有見地的解釋(盡管要注意他的一些較舊的出版物/文章發現包含一些隱藏/不可預見的問題)。

你可以試試這個庫,它是用 c 本機構建的。 隊列

例如

int* int_data;
lfqueue_t my_queue;

if (lfqueue_init(&my_queue) == -1)
    return -1;

/** Wrap This scope in other threads **/
int_data = (int*) malloc(sizeof(int));
assert(int_data != NULL);
*int_data = i++;
/*Enqueue*/
 while (lfqueue_enq(&my_queue, int_data) == -1) {
    printf("ENQ Full ?\n");
}

/** Wrap This scope in other threads **/
/*Dequeue*/
while  ( (int_data = lfqueue_deq(&my_queue)) == NULL) {
    printf("DEQ EMPTY ..\n");
}

// printf("%d\n", *(int*) int_data );
free(int_data);
/** End **/

lfqueue_destroy(&my_queue);

(暫時離開這里,但請參閱編輯。)

你知道 C 語言中無鎖隊列的實現嗎?

我最近寫了無鎖隊列( http://www.ideone.com/l2QRp )。 我實際上不能保證它正常工作,但我找不到任何錯誤,而且我已經在幾個單線程程序中使用它沒有任何問題,所以它沒有什么太明顯的錯誤。

簡單的用法示例:

queue_t queue;
int val = 42;
queue_init(&queue,sizeof val);
queue_put(&queue,&val);
val = 0; 
queue_pop(&queue,&val);
printf("%i\n",val); // 42
queue_destroy(&queue);

編輯:

正如@Alexey Kukanov 所指出的,如果tmp被彈出、釋放、再次分配,並在檢查空值和交換之間再次放置,則 queue_pop 可能會失敗:

    if(!tmp->next) return errno = ENODATA;
    /* can fail here */
    } while(!sync_swap(q->head,tmp,tmp->next));

我還不確定如何解決這個問題,但我會(希望)在我弄清楚后更新它。 暫時先不管這個。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM