執行緒安全的佇列實現(CAS與鎖)

2021-10-23 13:51:59 字數 4321 閱讀 8682

一、陣列實現執行緒安全的迴圈佇列

cas函式如下:bool succ =

__sync_bool_compare_and_swap

(&a, b, c)

//---》 if(a ==b ) else

struct queue

;int maxsize=

10000

;queue* q;

intpush

(int d)

intpop

(int

&d)int

pop2

(int

& d)

return0;

}

二、陣列實現執行緒安全的棧
int stack[

10000];

int maxsize=

10000

;int top=-1

;int

push

(int number)

else

}int

pop(

int&d)

else

}int

pop2

(int

&d)//cas

d=stack[temp]

;while(!

__sync_bool_compare_and_swap

(top,temp,temp--

)return0;

}

三、利用鎖實現執行緒安全的佇列
#include

#include

#include

#include

#include

template

class threadsafequeue

threadsafequeue

(threadsafequeue const

& other)

void

push

(t new_value)

//入隊

void

wait_and_pop

(t& value)

//直到有元素可以刪除為止);

value = data_queue.

front()

; data_queue.

pop();

} std:

:shared_ptr

wait_and_pop()

);std:

:shared_ptr

res(std:

:make_shared

(data_queue.

front()

)); data_queue.

pop();

return res;

} bool try_pop

(t& value)

//不管有無元素直接返回

std:

:shared_ptr

try_pop()

bool empty()

const};

/*測試***/

//test

void

preparedata

(threadsafequeue<

int>

& queue)

}void

processdata

(threadsafequeue<

int>

& queue)

}int

main()

四、利用cas實現執行緒安全的迴圈佇列

普通佇列一般由陣列構成,都是先進先出。計算從隊頭開始處理,前面的處理完後,計算機移到下乙個單元處理 。這樣的話,前面的儲存單元用完後就空著,要知道佇列容量是有限的,這樣便造成了佇列的空間浪費。環形佇列能夠很好的解決這個儲存空間效率的問題,它有如下特點。它是乙個首尾相連的fifo的資料結構,採用陣列的線性空間,資料組織簡單。能很快知道佇列是否滿為空。能以很快速度的來訪問資料。因為有簡單高效的原因,甚至在硬體都實現了環形佇列。環形佇列廣泛用於網路資料收發,和不同程式間資料交換(比如核心與應用程式大量交換資料,從硬體接收大量資料)均使用了環形佇列。

環形佇列原理:**記憶體上沒有環形的結構,因此環形佇列實上是陣列的線性空間來實現。**那當資料到了尾部如何處理呢?它將轉回到0位置來處理。這個的轉回是通過取模操作來執行的。因此環列佇列的是邏輯上將陣列元素q[0]與q[maxn-1]連線,形成乙個存放佇列的環形空間。為了方便讀寫,還要用陣列下標來指明佇列的讀寫位置。head/tail.其中head指向可以讀的位置,tail指向可以寫的位置。

struct queue

;int maxsize=

10000

;queue* q;

intpush

(int d)

intpop

(int

&d)

cas操作——compare and set 或是 compare and swap,比較並交換是原子操作的一種,可用於在多執行緒程式設計中實現不被打斷的資料交換操作,從而避免多執行緒同時改寫某一資料時由於執行順序不確定性以及中斷的不可預知性產生的資料不一致問題。該操作通過將記憶體中的值與指定值oldval進行比較,當記憶體中的值與oldval一樣時將記憶體中的值替換為新值newval。現在幾乎所有的cpu指令都支援cas的原子操作,x86下對應的是 cmpxchg 彙編指令。有了這個原子操作,我們就可以用其來實現各種無鎖(lock free)的資料結構。

/*

mflagarray中的元素標記marray中與之對應的元素位置是否有效。mflagarray中的元素有4個取值:

0表示對應的marray中的槽位為空;

1表示對應槽位已被申請,正在寫入;

2表示對應槽位中為有效的元素,可以對其進行出對操作;

3則表示正在彈出操作

*/template class lockfreequeue

~lockfreequeue()

/** * 初始化queue。分配記憶體,設定size

* 非執行緒安全,需在單執行緒環境下使用

*/bool initialize()

const

intcapacity

(void

)const

const

intsize

(void

)const

/** * 入隊函式,執行緒安全

*/bool push

(const elementt & ele)

兩個入隊執行緒之間的同步

int update_tail_index =

(curtailindex +1)

% mcapacity;

// 如果已經被其他的執行緒更新過,則不需要更新;

// 否則,更新為 (curtailindex+1) % mcapacity;

__sync_bool_compare_and_swap

(&mtail, curtailindex, update_tail_index)

;// 申請到可用的儲存空間

*(marray + curtailindex)

= ele;

// 寫入完畢

__sync_fetch_and_add

(cur_tail_flag_index,1)

;// 更新size;入隊執行緒與出隊執行緒之間的協作

__sync_fetch_and_add

(&msize,1)

;return true;

}/**

* 出隊函式,執行緒安全

*/bool pop

(elementt *ele)

// 取模操作可以優化

int update_head_index =

(cur_head_index +1)

% mcapacity;

__sync_bool_compare_and_swap

(&mfront, cur_head_index, update_head_index)

;*ele =

*(marray + cur_head_index)

;// 彈出完畢

__sync_fetch_and_sub

(cur_head_flag_index,3)

;// 更新size

__sync_fetch_and_sub

(&msize,1)

;return true;}}

;

執行緒安全與鎖

1 原子操作 操作只有一步,不會被其他的操作打斷 2 系統一般會帶有一些原子操作的函式留給使用者使用,但是數量較少,並且一般只能用於簡單特定的場合 1 鎖就是乙個flag,他的作用是說現在某個資源正在被某個執行緒使用,別的執行緒都別想輕易的拿去使用,巨集觀上表現就好像是給這些資源新增了乙個鎖,被鎖住...

執行緒安全與鎖優化

樂觀鎖 cas aba 版本號 atomicstampedreference 時間戳atomicmarkablereference boolean 可重入 絕對執行緒安全,不依賴共享資料 使用引數,區域性變數 自旋鎖 認為鎖很快釋放,占用cpu迴圈獲取鎖,超過一定次數 時間 再掛起執行緒,自旋次數上...

多執行緒安全無鎖訊息佇列

技術介紹 cas 原子操作 是有cpu提供的原子操作。mydeque 入隊操作 void enqueue t value 通過援助操作,更新tail cas tail,tail,tail next 出對操作 t dequeue t temvalue q value recycle q 空間 retu...