1. 程式人生 > >C++互斥量、原子鎖、自旋鎖等比較

C++互斥量、原子鎖、自旋鎖等比較

現象:

(1)單執行緒無鎖速度最快,但應用場合受限;

(2)多執行緒無鎖速度第二快,但結果不對,未保護臨界程式碼段;

(3)多執行緒原子鎖第三快,且結果正確;

(4)多執行緒互斥量較慢,慢與原子鎖近10倍,結果正確;

(5)多執行緒自旋鎖最慢,慢與原子鎖30倍,結果正確。

結論:原子鎖速度最快,互斥量和自旋鎖都用保護多執行緒共享資源。

       自旋鎖是一種非阻塞鎖,也就是說,如果某執行緒需要獲取自旋鎖,但該鎖已經被其他執行緒佔用時,該執行緒不會被掛起,而是在不斷的消耗CPU的時間,不停的試圖獲取自旋鎖。
       互斥量是阻塞鎖,當某執行緒無法獲取互斥量時,該執行緒會被直接掛起,該執行緒不再消耗CPU時間,當其他執行緒釋放互斥量後,作業系統會啟用那個被掛起的執行緒,讓其投入執行。

       在多處理器環境中對持有鎖時間較短的程式來說使用自旋鎖代替一般的互斥鎖往往能提高程式的效能,但是本程式碼無該效果。

#include <iostream>
#include <atomic>
#include <mutex>
#include <thread>
#include <vector>

class spin_mutex {
    std::atomic<bool> flag = ATOMIC_VAR_INIT(false);
public:
    spin_mutex() = default;
    spin_mutex(const spin_mutex&) = delete;
    spin_mutex& operator= (const spin_mutex&) = delete;
    void lock() {
        bool expected = false;
        while (!flag.compare_exchange_strong(expected, true))
            expected = false;
    }
    void unlock() {
        flag.store(false);
    }
};

long size = 1000000;
long total = 0;
std::atomic_long total2(0);
std::mutex m;
spin_mutex lock;

void thread_click()
{
    for (int i = 0; i < size; ++i)
    {
        ++total;
    }
}

void mutex_click()
{
    for (int i = 0; i < size; ++i)
    {
        m.lock();
        ++total;
        m.unlock();
    }
}

void atomic_click()
{
    for (int i = 0; i < size; ++i)
    {
        ++total2;
    }
}


void spinlock_click()
{
    for (int i = 0; i < size; ++i)
    {
        lock.lock();
        ++total;
        lock.unlock();
    }
}

int main()
{
    int thnum = 100;
    std::vector<std::thread> threads(thnum);
    clock_t start, end;

    total = 0;
    start = clock();
    for (int i = 0; i < size * thnum; i++) {
        ++total;
    }
    end = clock();
    std::cout << "single thread result: " << total << std::endl;
    std::cout << "single thread time: " << end - start << std::endl;

    total = 0;
    start = clock();
    for (int i = 0; i < thnum; ++i) {
        threads[i] = std::thread(thread_click);
    }
    for (int i = 0; i < thnum; ++i) {
        threads[i].join();
    }
    end = clock();
    std::cout << "multi thread no mutex result: " << total << std::endl;
    std::cout << "multi thread no mutex time: " << end - start << std::endl;

    total = 0;
    start = clock();
    for (int i = 0; i < thnum; ++i) {
        threads[i] = std::thread(atomic_click);
    }
    for (int i = 0; i < thnum; ++i) {
        threads[i].join();
    }
    end = clock();
    std::cout << "multi thread atomic result: " << total2 << std::endl;
    std::cout << "multi thread atomic time: " << end - start << std::endl;

    total = 0;
    start = clock();
    for (int i = 0; i < thnum; ++i) {
        threads[i] = std::thread(mutex_click);
    }
    for (int i = 0; i < thnum; ++i) {
        threads[i].join();
    }
    end = clock();
    std::cout << "multi thread mutex result: " << total << std::endl;
    std::cout << "multi thread mutex time: " << end - start << std::endl;

    total = 0;
    start = clock();
    for (int i = 0; i < thnum; ++i) {
        threads[i] = std::thread(spinlock_click);
    }
    for (int i = 0; i < thnum; ++i) {
        threads[i].join();
    }
    end = clock();
    std::cout << "spin lock result: " << total << std::endl;
    std::cout << "spin lock time: " << end - start << std::endl;
    getchar();
    return 0;
}

/*
single thread result: 100000000
single thread time: 231
multi thread no mutex result: 11501106
multi thread no mutex time: 261
multi thread atomic result: 100000000
multi thread atomic time: 1882
multi thread mutex result: 100000000
multi thread mutex time: 16882
spin lock result: 100000000
spin lock time: 45063
*/

相關推薦

機制-偏向輕量級重量級

自旋鎖 如果持有鎖的執行緒能在很短時間內釋放鎖資源,那麼那些等待競爭鎖的執行緒就不需要做核心態和使用者態之間的切換進入阻塞掛起狀態,只需讓執行緒執行一個忙迴圈(自旋),等持有鎖的執行緒釋放鎖後即可立即獲取鎖,這樣就避免使用者執行緒和核心的切換的消耗。 自旋等

執行緒同步機制(互斥,讀寫,條件變數,屏障)

先知:      (1)執行緒是由程序建立而來,是cpu排程的最小單位。      (2)每個程序都有自己獨立的地址空間,而程序中的多個執行緒共用程序的資源,他們只有自己獨立的棧資源。 執行緒同步:      當多個控制執行緒共享相同的記憶體時,需要確保每個程序看到一致的

Java 中15種的介紹:公平,可重入,獨享互斥,樂觀,分段等等

Java 中15種鎖的介紹 在讀很多併發文章中,會提及各種各樣鎖如公平鎖,樂觀鎖等等,這篇文章介紹各種鎖的分類。介紹的內容如下: 公平鎖 / 非公平鎖 可重入鎖 / 不可重入鎖 獨享鎖 / 共享鎖 互斥鎖 / 讀寫鎖 樂觀鎖 / 悲觀鎖 分段鎖

偏向,輕量級,重量級的詳細介紹

何為同步?JVM規範規定JVM基於進入和退出Monitor物件來實現方法同步和程式碼塊同步,但兩者的實現細節不一樣。程式碼塊同步是使用monitorenter和monitorexit指令實現,而方法同步是使用另外一種方式實現的,細節在JVM規範裡並沒有詳細說明,但是方法的同步

java同步優化方案學習筆記(偏向,輕量級,重量級

目錄 一,概述 二,CAS 一,概述 什麼是java的鎖? 為什麼java要有鎖? java的鎖為什麼需要優化? 怎麼優化的? 1,java中使用synchronized關鍵字來實現同步功能,被synchronized修飾的方法

JAVA機制-可重入,可中斷,公平,讀寫

部落格引用處(以下內容在原有部落格基礎上進行補充或更改,謝謝這些大牛的部落格指導): JAVA鎖機制-可重入鎖,可中斷鎖,公平鎖,讀寫鎖,自旋鎖 在併發程式設計中,經常遇到多個執行緒訪問同一個 共享資源 ,這時候作為開發者必須考慮如何維護資料一致性,在java中synchronized

虛擬機器內的優化(偏向,輕量級,重量級

基礎知識之一:鎖的型別 鎖從巨集觀上分為:(1)樂觀鎖;(2)悲觀鎖。 (1)樂觀鎖 樂觀鎖是一種樂觀思想,即認為讀多寫少,遇到併發寫的可能性低,每次去拿資料的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個

Java詳解

並且 port stat static 進入 屬性 ESS 節點 round 鎖作為並發共享數據,保證一致性的工具, 在JAVA平臺有多種實現(如 synchronized 和 ReentrantLock等等 ) 。這些已經寫好提供的鎖為我們開發提供了便利

C++互斥原子比較

現象: (1)單執行緒無鎖速度最快,但應用場合受限; (2)多執行緒無鎖速度第二快,但結果不對,未保護臨界程式碼段; (3)多執行緒原子鎖第三快,且結果正確; (4)多執行緒互斥量較慢,慢與原子鎖近10倍,結果正確; (5)多執行緒自旋鎖最慢,慢與原子鎖30倍,結果

[Linux]互斥機制(中斷遮蔽原子操作訊號

基本概念 臨界區 對某段程式碼而言,可能會在程式中多次被執行,每次執行的過程我們稱作程式碼的執行路徑。 當兩個或多個程式碼路徑要競爭共同的資源的時候,該程式碼段就是臨界區。 互斥機制 訪問共享資源的程式碼叫做臨界區。共享資源被多個執行緒需要

互斥原子操作訊號

一、互斥體 struct mutex my_mutex;//定義mutex mutex_init(&my_mutex);//初始化mutex mutex_lock(&my_mutex);//獲取mutex ... //臨界資源 mutex_unlock(&

互斥體和訊號

自旋鎖 Linux核心中最常見的鎖是自旋鎖(spin lock)。自旋鎖最多隻能被一個可執行執行緒持有。如果一個執行執行緒試圖獲得一個被已經持有的自旋鎖,那麼該執行緒就會一直進行忙迴圈——旋轉——等待鎖重新可用。要是鎖未被爭用,請求鎖的執行執行緒便能立刻得到它,繼續執行。在任意時間,自旋鎖都

管理訊號原子變數函式介面>>Linux 裝置驅動程式

文章目錄 [0x100] 程序競態特徵 [0x200] 訊號量 [0x210] 程序訊號量函式介面[struct semaphore] [0x211] 初始化訊號量 [0x212] 獲取與釋放訊號量 [0x2

多執行緒——原子原子互斥

nonatomic:非原子屬性,執行緒不安全的,效率高 atomic:原子屬性,執行緒安全的,效率相對低。 原子屬性是一種單(執行緒)寫多(執行緒)讀的多執行緒技術,不過可能會出現髒資料 atomi

原子操作訊號讀寫訊號的區別與聯絡

一.為什麼核心需要同步方法 併發指的是多個執行單元同時,並行被執行,而併發的執行單元對共享資源(硬體資源和軟體上的全域性變數,靜態變數等)的訪問則很容易導致競態。 主要競態發生如下: 1.對稱多處理器(SMP)多個CPU  SMP是一種緊耦合,共享儲存的系統模型,它的特點是多個CPU使用共同的系統匯流排,因此

linux核心 訊號延時函式比較

       在驅動程式中,當多個執行緒同時訪問相同的資源時(驅動程式中的全域性變數是一種典型的共享資源),可能會引發"競態",因此我們必須對共享資源進行併發控制。Linux核心中解決併發控制的最常用方法是自旋鎖與訊號量(絕大多數時候作為互斥鎖使用)。   自

互斥的對比手工實現

                    本文之前,我只是對自旋鎖有所瞭解,知道它是做什麼的,但是沒有去測試實現過,甚至以為自旋鎖只有kernel用這個,今天才發現POSIX有提供自旋鎖的介面。下面我會分析一下自旋鎖,並程式碼實現自旋鎖和互斥鎖的效能對比,以及利用C++11實現自旋鎖。 一:自旋鎖(s

原子操作 訊號 互斥

核心同步措施(用於linux核心)    為了避免併發,防止競爭。核心提供了一組同步方法來提供對共享資料的保護。 我們的重點不是介紹這些方法的詳細用法,而是強調為什麼使用這些方法和它們之間的差別。    Linux使用的同步機制可以說從2.0到2.6以來不斷髮展完善。從最初的原子操作,到後來的訊號量,從大核心

使用者態讀寫互斥

1、自旋鎖 自旋鎖最多可能被一個可執行執行緒所持有。一個被徵用的自旋鎖使得請求它的執行緒在等待鎖重新可用時自旋(特別浪費處理器時間)。所以自旋鎖不應該被長時間持有。 自旋鎖是不可遞迴的! (1)自旋鎖相關函式 使用者態的自旋鎖相關函式包含在標頭檔案<pthr

核心下各種同步處理方法(訊號燈互斥體…)

轉自:http://www.blogfshare.com/kernel-synchronization.html 1.在支援多執行緒的作業系統下,有些函式會出現不可重入的現象。所謂“可重入”是指函式的執行結果不和執行順序有關。反之如果執行結果和執行順序有關,則稱這個函式是