互斥條件:指程序對所分配到的資源進行排它性使用,即在一段時間內某資源只由乙個程序占用。如果此時還有其它程序請求資源,則請求者只能等待,直至占有資源的程序用畢釋放。
請求和保持條件:指程序已經保持至少乙個資源,但又提出了新的資源請求,而該資源已被其它程序占有,此時請求程序阻塞,但又對自己已獲得的其它資源保持不放。
不剝奪條件:指程序已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放。
環路等待條件:指在發生死鎖時,必然存在乙個程序——資源的環形鏈,即程序集合中的p0正在等待乙個p1占用的資源;p1正在等待p2占用的資源,……,pn正在等待已被p0占用的資源。
例子:
class
some_big_obj
;void
swap
(some_big_obj& lhs, some_big_obj& rhs)
;class
xfriend
void
swap
(x& lhs, x& rhs)
private
: some_big_obj some_detail;
std::mutex m;
};
上面的1處和2處分別鎖住了兩個互斥量,假如執行緒a在執行1的時候,執行緒切換d到b,b執行緒鎖住了rhs的鎖,並開始嘗試鎖住lhs的鎖,但是發現lhs的鎖已經被鎖住了(被a鎖住了),所以b執行緒發生了阻塞。然後執行緒切換回a,開始去嘗試鎖住rhs,但是rhs此時已經被b執行緒鎖住了,此時a執行緒也發生了阻塞。兩個執行緒會分別等待對方釋放另乙個鎖,所以就無限等待了。
解決方法:
class
some_big_obj
;void
swap
(some_big_obj& lhs, some_big_obj& rhs)
;class
xfriend
void
swap
(x& lhs, x& rhs)
private
: some_big_obj some_detail;
std::mutex m;
};
有兩種方法:
直接使用c++17標準的std::scope_lock
模板類,此模板類可以同時鎖定多個互斥量,並且能夠在析構時自動解鎖互斥量;
使用c++11標準的std::lock()
模板函式和std::lock_guard
模板類,通過函式std::lock()
鎖定多個互斥量,然後通過std::lock_guard
類負責互斥量的解鎖。其中,std::adopt_lock
表示只構造物件,但不鎖定互斥量。
例子:
std::mutex m;
voidf(
)int
main()
上述過程可能導致在2處上鎖,然後子執行緒在1處發生阻塞,最後主線程在3處一直等待子執行緒結束,無窮等待下去。
解決方法:
主線程對互斥量上鎖要放到join()
之後;
std::thread t
(f);
// ...
t.join()
;// ...
std::lock_guard lock
(m);
// ...
主線程對互斥量上鎖放到乙個區域性作用域內。
std::thread t
(f);
t.join()
;
因為使用者提供的**中很可能也有鎖,這樣的話,在同乙個過程可能就會訪問多個鎖,可能會產生第1點所描述的死鎖。
比如多執行緒下對於鍊錶的操作。假如保護鍊錶的鎖的粒度很小,每個節點擁有乙個互斥量,這樣能夠最大化並行效率。在這種情況下,當乙個執行緒刪除鍊錶中的乙個節點時,它必須獲取3個節點上的互斥量:將要刪除的節點,兩個鄰接節點。
執行緒1執行緒2
鎖住主入口的互斥量
讀取頭節點指標
鎖住頭節點互斥量
解鎖主入口互斥量
鎖住主入口互斥量
讀取head->next指標
鎖住尾結點互斥量
鎖住next節點互斥量
讀取tail->prev指標
讀取next->next指標
解鎖尾結點互斥量……
鎖住a節點互斥量
鎖住c節點互斥量
讀取a->next指標(也就是b節點)
讀取c->next指標(也就是b節點)
鎖住b節點互斥量
阻塞,嘗試鎖住b節點互斥量
解鎖c節點互斥量
讀取b->prev指標(也就是a節點)
阻塞,嘗試鎖住a節點互斥量
死鎖死鎖
由於這裡獲取三個鎖不是同時的,是分步獲取的,所以不能夠使用std::scoped_lock
,所以就會產生上述的死鎖。
避免這種死鎖的方式就是定義遍歷的順序,乙個執行緒必須先鎖住a才能獲取b的鎖,在鎖住b之後才能獲取c的鎖。
在某些情況下,設定鎖的大小,使得乙個執行緒中獲取多個鎖時,只能按照順序來進行上鎖,如果順序錯了,直接丟擲異常,這樣就能避免死鎖。
層次鎖的實現例子:
class
hierarchical_mutex
void
update_hierarchy_value()
public
:explicit
hierarchical_mutex
(unsigned
long value)
:hierarchy_value
(value)
,previous_hierarchy_value(0
)void
lock()
void
unlock()
bool
try_lock()
};thread_local
unsigned
long hierarchical_mutex::
this_thread_hierarchy_value
(ulong_max)
;
其中,thread_local
型別用於執行緒區域性儲存(stl)。需要注意的是,如果想讓自定義鎖型別能夠使用標準庫的std::lock()
或std::lock_guard
,則必須自己實現類成員函式lock()
,unlock()
和try_lock()
。
層次鎖的使用例子:
hierarchical_mutex high_level_mutex
(10000);
hierarchical_mutex low_level_mutex
(5000);
hierarchical_mutex other_mutex
(6000);
intdo_low_level_stuf()
;int
low_level_func()
void
do_high_level_stuff
(int some_param)
;void
high_level_func()
void
thread_a()
void
do_other_stuff()
;void
other_func()
void
thread_b()
上述例子中,thread_a
執行緒先得到標記為10000的鎖,然後又得到標記為5000的鎖,因此能正常執行。而thread_b
先得到標記為6000的鎖,然後又嘗試獲取標記為10000的鎖,這裡就會出錯,因為獲取鎖的順序出錯了,最後會丟擲異常。 死鎖產生原因及解決方法
死鎖 執行緒級 死鎖是指兩個或兩個以上的執行緒在執行過程中,由於競爭資源而造成的一種阻塞的現象 產生的4個條件 1 互斥使用 即乙個執行緒在使用時,另外執行緒不可使用 2 不可搶占資源 資源請求者不能強制從資源佔有者手中奪取資源 3 占有且等待 當前執行緒在請求其他資源時,保持對原有資源占有 4 迴...
死鎖的產生條件及解決方法
產生死鎖的原因主要是 1 因為系統資源不足。2 程序執行推進的順序不合適。3 資源分配不當等。如果系統資源充足,程序的資源請求都能夠得到滿足,死鎖出現的可能性就很低,否則 就會因爭奪有限的資源而陷入死鎖。其次,程序執行推進順序與速度不同,也可能產生死鎖。產生死鎖的四個必要條件 1 互斥條件 乙個資源...
解決產生oracle sql死鎖
1 查詢資料庫死鎖 可以檢視產生死鎖的使用者,死鎖狀態,狀態,產生死鎖的機器和應用程式 2 查詢產生死鎖的語句 select sql text from v sql where hash value in select sql hash value from v session where sid ...