多執行緒模型下的無鎖程式設計
在多執行緒程式設計模型下,解決竟態條件的傳統方法就是加鎖保護臨界區,但這存在影響系統性能、優先順序反轉等問題.
因此又有人提出了,多執行緒模型下無鎖程式設計的一些方式:
1.執行緒內通訊框架: Disruptor, 這是一款開源的併發框架,用於執行緒間無鎖的共享資料,看這裡。
2.無鎖資料結構
無鎖資料結構一般基於一個很重要的操作:CAS--Compare And Swap(看這裡)。
用C語言表達的一個CAS實現的操作是這樣的:
-
/*定義CAS操作*/
-
#define CAS __sync_bool_compare_and_swap
-
/*
-
* 定義stack的資料結構
-
*/
-
typedef struct stack_node {
-
struct node *next;
-
void *data;
-
}stack_node;
-
/*棧頂指標*/
- stack_node *top = NULL;
CAS的一個重要特性是其必須是原子操作。現在大多數CPU都支援指令級別的CAS操作。GCC編譯也提供了這樣的介面:bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)
有了這個原子的CAS後,我們就能實現自己的無鎖資料結構了,下面我們就嘗試著來實現一個無鎖棧:
下面的程式碼中,我們假設malloc與free是執行緒安全的(至於malloc與free的可重入性與執行緒安全問題,可以看這裡和這裡)
首先定義必要的資料結構:
-
/*定義CAS操作*/
-
#define CAS __sync_bool_compare_and_swap
-
/*
-
* 定義stack的資料結構
-
*/
-
typedef struct stack_node {
-
struct node *next; /*指向下一個節點,即通過連結串列的形式實現棧*/
-
void *data;/*指向該節點的資料*/
-
}
-
/*棧頂指標*/
- stack_node *top = NULL;
-
/*壓棧操作*/
-
void stack_push(void *data)
-
{
-
stack_node *new = malloc(sizeof(struct node));
-
new->data = data;
-
do {
-
new->next = top;/*獲取top的快照, 同時初始化了new的next指標*/
-
}while(!CAS(&top, new->next, new));
- }
假設有執行緒A在stack_push裡獲取top快照後暫時失去了執行權, 切換至另一個執行緒B, 而執行緒B完成了一次stack_push操作,然後執行權再次回到執行緒A,
執行緒A執行CAS操作, 發現top裡的內容與快照裡的內容已經不一致了,CAS返回false, 估do...while語句重新執行。
接下來是出棧操作:
-
/*出棧操作*/
-
void * stack_pop(void)
-
{
-
stack_node *tmp;
-
void *data;
-
do {
-
tmp = top;
-
if (!tmp) return NULL;
-
}while(CAS(&top, tmp, tmp->next) = true);
-
data = tmp->data;
-
free(tmp);
-
return data;
- }
另外還有一點, 在使用CAS實現免鎖資料結構時, 容易出現ABA問題, 這裡也暫時不作討論, 可以從參考資料中得到更多的資訊。
參考資料:
1.來自酷客的無鎖佇列
2.設計不用互斥鎖的併發資料結構
轉載自:http://blog.chinaunix.net/uid-25424552-id-3772253.html
相關推薦
多執行緒模型下的無鎖程式設計
多執行緒模式是比較流行的一種併發程式設計模型,多執行緒程式設計的一個特點就是執行緒間共享記憶體空間;這可以降低執行緒間通訊的開銷,但卻引來了另外的一個難纏的問題:竟態條件!,因此,甚至有人對多執行緒模型提出了質疑,看這裡。在多執行緒程式設計模型下,解決竟態條件的傳統方法就是
c++多執行緒模式下的socket程式設計(執行緒池實現)
socket 程式設計可以說是一個基本的技術掌握,而多個客戶端向服務端傳送請求又是一個非常常見的場景,因此多執行緒模式下的socket程式設計則顯得尤為常見與重要。 本文主要利用執行緒池的技術,來實現多執行緒的模式,執行緒池的優點就不多述了,相信大家都能理
一種多執行緒基於計數無鎖實現(C#)(轉載)
轉自:http://blog.csdn.net/chzuping/article/details/10960061 chzuping的專欄 本文介紹一種不加鎖,不使用原子操作的多執行緒同步機制。先申明下,該方案為我在實際程式設計中創造出來的,事先我沒有在其中地方
socket程式設計多執行緒模型
/*問題 1.調整程序內的最大檔案描述符上限 2.執行緒如有共享資料,考慮執行緒同步 3.服務與客戶端執行緒退出時,退出處理 4.系統負載,隨著連結客戶端增加,導致其他執行緒不能及時得到CPU */ /*server.c*/ #include <stdio.h> #includ
多執行緒 共享資源 同步鎖 java Java多執行緒程式設計:Lock
Java多執行緒程式設計:Lock synchronized是java中的一個關鍵字,也就是說是Java語言內建的特性。那麼為什麼會出現Lock呢? 如果一個程式碼塊被synchronized修飾了,當一個執行緒獲取了對應的鎖,並執行該程式碼塊時,其他執行緒便只
localtime_r在多執行緒環境下可能存在死鎖
但是在某些情況下,localtime_r可能存在死鎖的情況,使用如下的測試程式: #include <pthread.h> #include <time.h> void *mytest(void *arg) { pthrea
網路程式設計之多執行緒——GIL全域性直譯器鎖
網路程式設計之多執行緒——GIL全域性直譯器鎖 一、引子 定義: In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python b
OSG 多執行緒模型 設計思想
A New Processing Model for Multithreaded, Multidisplay Scene Graphs Copyright © 2001 Don Burns (DB - Apr 28, 2004) This article
多執行緒基礎5 Lock 鎖
1.同步 * 使用ReentrantLock類的lock()和unlock()方法進行同步 2.通訊 * 使用ReentrantLock類的newCondition()方法可以獲取Condition物件 * 需要等待的時候使用Condition的await()方法, 喚醒的時候用signal()
java多執行緒中顯式鎖的輪詢檢測策略
顯式鎖簡介 java5.0之前,在協調對共享物件的訪問時可以使用的機制只有synchronized和volatile,java5.0增加了一種新的機制:ReentrantLock。 鎖像synchronized同步塊一樣,是一種執行緒同步機制,與synchronized不同的是ReentrantLock提
【JAVA多執行緒問題之死鎖】
一、死鎖是什麼? 舉個例子:兩個人一起吃飯,每個人都拿了一隻筷子,雙方都在等待對方將筷子讓給自己,結果兩個人都吃不了飯。這種情況和計算機中的死鎖情況很相似。 假設有兩個執行緒,互相等待對方釋放佔有的鎖,但是釋放鎖的條件又不可能形成,這時候死鎖就形成了。 還是買票的問題,有的時候時會發生死
多執行緒學習----讀寫鎖的使用(十二)
讀寫鎖 讀寫鎖:分為讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖和寫鎖互斥,這是由jvm自己控制的,你只要上好相應的鎖即可。如果你的程式碼只讀資料,可以很多人同時讀,但是不能同時寫,那就讓讀鎖;如果你的程式碼修改資料,只能有一個人在寫,且不能同時讀
gdb除錯多執行緒出現的死鎖
多執行緒的條件下,程式很容易出現死鎖,此時各個執行緒處於等待狀態,可以通過gdb除錯找到死鎖出現的地方。 例子: #include <stdio.h> #include <pthread.h> #include <uni
多執行緒-day-10顯示鎖
目錄 顯示鎖 Lock介面和核心方法 Lock和synchronized關鍵字的比較 可重入鎖ReentrantLock、公平鎖、非公平鎖 讀寫鎖 Condition介面 用Lock和Condition實現等待和通知 一、Lock介面和核心方法  
java多執行緒:5.1 鎖-基礎
什麼是鎖 提到多執行緒,立馬就有人說加鎖,什麼是鎖,為什麼加鎖? 鎖:從字面意義,什麼東西加了鎖,那麼就只有有鑰匙的人才能使用,多執行緒中的鎖,也是這個意思。 為什麼加鎖:當單執行緒的時候,無論訪問什麼資源,都不需要考慮鎖的問題,但是當多個執行緒訪問同一個資源,就會發生很多千奇百怪的
HashMap多執行緒環境下的死迴圈問題解釋
hashMap在多執行緒環境下,呼叫put方法出現的死迴圈是由於擴容時候resize方法導致的連結串列出現迴圈。 void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity =
基於Log4j NDC 多執行緒條件下記錄日誌,排查生產問題
在大吞吐,高併發的場景, 一個請求到達後端,通常是轉換成多執行緒並行處理請求, 如何通過一個標誌找到這個請求對應的多個執行緒,瞭解這個請求的完整的處理情況,從而幫助我們定位這次呼叫到底哪一步出現了問題,對我們快速定位排查生產問題是非常有用的。我們在每個子任務程式
java day25 多執行緒(下) 單例類(Runtime,Timer
25.01_多執行緒(單例設計模式)(掌握) 單例設計模式:保證類在記憶體中只有一個物件。 如何保證類在記憶體中只有一個物件呢? (1)控制類的建立,不讓其他類來建立本類的物件。private (2)在本類中定義一個本類的物件。Singl
java多執行緒--簡易使用同步鎖實現一對一交替列印
一、本例需要分析的地方不多,只需要使用一個同步鎖+一個計數器就能搞定,直接奉送原始碼吧: package com.example.liuxiaobing.statemodel.mutil_thr
為什麼EventLoop能避免多執行緒併發操作和鎖競爭
Netty的Reactor執行緒池就是EventLoopGroup,是一個EventLoop的陣列。EventLoop是用來處理所有註冊到自身這個執行緒的Selector上的channel,Selector的輪詢操作由EventLoop的run方法驅動,在一個迴圈體內迴圈執行,包括使用者自定