併發高階 多核程式設計中的條件同步模式

2021-04-25 19:47:32 字數 2193 閱讀 8599

在多執行緒程式設計中,當對共享資源進行操作時,需要使用同步(通常是鎖或原子操作)來進行保護,以避免資料競爭問題。不幸的是,同步操作的開銷非常大,比如對乙個整數變數進行加法操作,那麼同步操作的開銷是加法操作的上百倍以上。

有沒有辦法可以減少這種同步操作的開銷呢?如果能設計出更快的鎖或更快的原子操作來,那麼這種開銷自然就減少了。以目前的技術來看,最快速的原子操作耗時也是普通加法操作的上百倍,所以從這方面著手是非常困難的。

那麼能不能從軟體演算法的角度來減少同步操作的開銷呢?答案是當然可以,基本思想是減少使用同步的次數,比如原來要使用同步

1000

次,現在改為在滿足一定條件下才使用同步,只需要

10次,那麼同步的開銷平攤下來就被減少了

100倍,效率大大提高了。下面先來看乙個共享佇列例子。

乙個普通的共享佇列通常都是使用鎖來實現,當然也有用

cas原子操作來實現的,這裡只討論用鎖來實現的共享佇列。

在有鎖保護的共享佇列中,在佇列的進隊和出隊操作時,通常都是使用鎖來進行保護的,乙個典型的使用鎖保護的出隊操作偽**如下:

template class

locked_dequeue(t &data)

在使用上面的

locked_dequeue()

函式時,每呼叫一次,就會發生一次鎖操作。事實上,並不是每次都需要加鎖操作的,比如隊列為空時,這時實際上是不需要進行出隊操作的,完全可以採取的一定的方法避免鎖操作,但是採用上面的

locked_dequeue()

函式無法避免鎖操作,這就需要對上面的函式進行改進。

一種最容易想到的方面就是先判斷佇列是否為空,如果不為空才使用鎖保護進行出隊操作。**如下:

template class

locked_dequeue_a(t &data)

}上面的

locked_dequeue_a()

函式的乙個關鍵之處是

isempty()

函式必須不能使用鎖操作,否則不僅沒有減少同步開銷,反而將同步開銷增大了近一倍。

如何來使得

isemtpy()

函式不用鎖操作呢,以陣列實現的環行隊列為例,在判斷佇列是否為空時,其基本方法是判斷隊首指標是否等於隊尾指標。偽**如下:

int isempty()

else

}由於隊首指標和隊尾指標在進隊或出隊操作時會發生改變,因此在上面的

isempty()

函式中,需要使用鎖保護,那麼如何去掉這層鎖保護呢?

基本的方法是設乙個標誌變數

emptyflag

,在進隊和出隊操作中,當隊列為空時,標誌變數的值置為

1,佇列非空時,標誌變數的值置為

0。這樣判斷佇列是否為空就可以通過

emptyflag

單個變數來進行,而單個變數的讀寫可以使用原子操作來實現,使得讀操作和普通操作一樣不存在同步操作。

下面是使用

emptyflag

變數實現的出隊操作。

template class

locked_dequeue_b(t &data)

lock();

if ( !emptyflag )//lock()前,

其他執行緒可能修改了標誌

}unlock();

}佇列的是否為空函式可以使用下面的完全不需要同步的實現。

int isempty()

從locked_dequeue_b()

函式的實現可以看出,如果佇列本來為空的情況下,它只判斷乙個

emptyflag

就返回了,不會呼叫鎖操作,減少了同步使用的次數,並且在

isempty()

函式中,根本不需要使用同步,這對於那些需要頻繁判斷佇列是否為空的使用場景,有很好的效果。

比如對於動態任務排程,假設使用普通的有鎖的共享佇列。當乙個執行緒私有隊列為空時,需要去偷取其他執行緒的共享佇列中的任務,如果偷取的隊列為空則發生了一次鎖操作,此時需要再偷另外乙個佇列的任務,如果這個佇列仍然為空則又要一次鎖操作,一次獲取任務的操作中將可能出現多次加鎖解鎖的情況。通過上面講的條件同步方法就可以在偷取取乙個任務時,只要一次鎖操作就可以實現。

上面講的條件同步模式非常適應於具有狀態機性質的場合,只有在發生狀態切換(例如佇列中空或非空的狀態的切換)時才使用同步,通過對狀態變數(例如

emptyflag

)的操作來替代其他非狀態變數

(例如隊首指標和隊尾指標

)的操作,減少同步的使用。

多核程式設計中的條件同步模式

多核程式設計中的條件同步模式 在多執行緒程式設計中,當對共享資源進行操作時,需要使用同步 通常是鎖或原子操作 來進行保護,以避免資料競爭問題。不幸的是,同步操作的開銷非常大,比如對乙個整數變數進行加法操作,那麼同步操作的開銷是加法操作的上百倍以上。有沒有辦法可以減少這種同步操作的開銷呢?如果能設計出...

多核程式設計中的鎖競爭難題

多核程式設計中的鎖競爭現象 多核程式設計中的負載平衡難題 多核程式設計的幾個難題及其應對策略 難題一 openmp並行程式設計 二 openmp並行程式設計 一 雙核cpu上的快速排序效率 在前一篇講解多核程式設計的幾個難題及其對策 難題一 的文章中提到了鎖競爭會讓序列化隨cpu的核數增多而加劇的現...

多核程式設計中的鎖競爭難題

多核程式設計中的鎖競爭現象 多核程式設計中的負載平衡難題 多核程式設計的幾個難題及其應對策略 難題一 openmp並行程式設計 二 openmp並行程式設計 一 雙核cpu上的快速排序效率 在前一篇講解多核程式設計的幾個難題及其對策 難題一 的文章中提到了鎖競爭會讓序列化隨cpu的核數增多而加劇的現...