中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

c++11線程需要互斥量的原因是什么

發布時間:2022-04-16 10:38:10 來源:億速云 閱讀:138 作者:iii 欄目:編程語言

本篇內容介紹了“c++11線程需要互斥量的原因是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

為什么需要互斥量

在多任務操作系統中,同時運行的多個任務可能都需要使用同一種資源。這個過程有點類似于,公司部門里,我在使用著打印機打印東西的同時(還沒有打印完),別人剛好也在此刻使用打印機打印東西,如果不做任何處理的話,打印出來的東西肯定是錯亂的。

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <chrono>
#include <thread>

// 打印機
void printer(const char *str)
{
    while(*str != '\0')
    {
        std::cout << *str;
        str++;
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
    std::cout << std::endl;
}

// 線程一
void func1()
{
    const char *str = "hello";
    printer(str);
}

// 線程二
void func2()
{
    const char *str = "world";
    printer(str);
}


void mytest()
{
    std::thread t1(func1);
    std::thread t2(func2);

    t1.join();
    t2.join();

    return;
}

int main()
{
    mytest();

    system("pause");
    return 0;
}

獨占互斥量std::mutex

互斥量的基本接口很相似,一般用法是通過lock()方法來阻塞線程,直到獲得互斥量的所有權為止。在線程獲得互斥量并完成任務之后,就必須使用unlock()來解除對互斥量的占用,lock()和unlock()必須成對出現。try_lock()嘗試鎖定互斥量,如果成功則返回true, 如果失敗則返回false,它是非阻塞的。

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <mutex>

std::mutex g_lock; //全局互斥鎖對象,#include <mutex>

// 打印機
void printer(const char *str)
{
    g_lock.lock(); //上鎖
    while(*str != '\0')
    {
        std::cout << *str;
        str++;
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
    std::cout << std::endl;
    g_lock.unlock(); // 解鎖
}

// 線程一
void func1()
{
    const char *str = "hello";
    printer(str);
}

// 線程二
void func2()
{
    const char *str = "world";
    printer(str);
}


void mytest()
{
    std::thread t1(func1);
    std::thread t2(func2);

    t1.join();
    t2.join();

    return;
}

int main()
{
    mytest();

    system("pause");
    return 0;
}

使用std::lock_guard可以簡化lock/unlock的寫法,同時也更安全,因為lock_guard在構造時會自動鎖定互斥量,而在退出作用域后進行析構時就會自動解鎖,從而避免忘了unlock操作。

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <mutex>

std::mutex g_lock; //全局互斥鎖對象,#include <mutex>

// 打印機
void printer(const char *str)
{
    std::lock_guard<std::mutex> locker(g_lock); // lock_guard 上鎖
    while(*str != '\0')
    {
        std::cout << *str;
        str++;
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
    std::cout << std::endl;
    // 即將推出作用域 lock_guard 會自動解鎖
}

// 線程一
void func1()
{
    const char *str = "hello";
    printer(str);
}

// 線程二
void func2()
{
    const char *str = "world";
    printer(str);
}


void mytest()
{
    std::thread t1(func1);
    std::thread t2(func2);

    t1.join();
    t2.join();

    return;
}

int main()
{
    mytest();

    system("pause");
    return 0;
}

原子操作

所謂的原子操作,取的就是“原子是最小的、不可分割的最小個體”的意義,它表示在多個線程訪問同一個全局資源的時候,能夠確保所有其他的線程都不在同一時間內訪問相同的資源。也就是他確保了在同一時刻只有唯一的線程對這個資源進行訪問。這有點類似互斥對象對共享資源的訪問的保護,但是原子操作更加接近底層,因而效率更高。

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <chrono>
#include <thread>

//全局的結果數據
long total = 0;

//點擊函數
void func()
{
    for(int i = 0;  i < 1000000; ++i)
    {
        // 對全局數據進行無鎖訪問
        total += 1;
    }
}


void mytest()
{
    clock_t start = clock();    // 計時開始

    //線程
    std::thread t1(func);
    std::thread t2(func);

    t1.join();
    t2.join();

    clock_t end = clock();    // 計時結束

    std::cout << "total = " << total << std::endl;
    std::cout << "time = " << end-start << " ms" << std::endl;


    return;
}

int main()
{
    mytest();

    system("pause");
    return 0;
}

由于線程間對數據的競爭而導致每次運行的結果都不一樣。因此,為了防止數據競爭問題,我們需要對total進行原子操作。

通過互斥鎖進行原子操作:

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <mutex>

std::mutex g_lock;

//全局的結果數據
long total = 0;

//點擊函數
void func()
{
    for(int i = 0;  i < 1000000; ++i)
    {
        g_lock.lock(); // 加鎖
        total += 1;
        g_lock.unlock(); // 加鎖
    }
}


void mytest()
{
    clock_t start = clock();    // 計時開始

    //線程
    std::thread t1(func);
    std::thread t2(func);

    t1.join();
    t2.join();

    clock_t end = clock();    // 計時結束

    std::cout << "total = " << total << std::endl;
    std::cout << "time = " << end-start << " ms" << std::endl;


    return;
}

int main()
{
    mytest();

    system("pause");
    return 0;
}

每次運行的結果都一樣,只是耗時長點。

在新標準C++11,引入了原子操作的概念。

如果我們在多個線程中對這些類型的共享資源進行操作,編譯器將保證這些操作都是原子性的,也就是說,確保任意時刻只有一個線程對這個資源進行訪問,編譯器將保證多個線程訪問這個共享資源的正確性。從而避免了鎖的使用,提高了效率。

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <atomic>

//原子數據類型
std::atomic<long> total(0); //需要頭文件 #include <atomic>

//點擊函數
void func()
{
    for(int i = 0;  i < 1000000; ++i)
    {
        // 
        total += 1;
    }
}


void mytest()
{
    clock_t start = clock();    // 計時開始

    //線程
    std::thread t1(func);
    std::thread t2(func);

    t1.join();
    t2.join();

    clock_t end = clock();    // 計時結束

    std::cout << "total = " << total << std::endl;
    std::cout << "time = " << end-start << " ms" << std::endl;


    return;
}

int main()
{
    mytest();

    system("pause");
    return 0;
}

原子操作的實現跟普通數據類型類似,但是它能夠在保證結果正確的前提下,提供比mutex等鎖機制更好的性能。

“c++11線程需要互斥量的原因是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

c++
AI

恭城| 宁德市| 大悟县| 修武县| 栾川县| 杭锦后旗| 通河县| 自治县| 东阿县| 沙河市| 浦城县| 小金县| 葵青区| 鄂托克旗| 福鼎市| 如东县| 来宾市| 汽车| 宁强县| 阜新| 吴旗县| 修文县| 张掖市| 怀安县| 房山区| 昌吉市| 陇南市| 邛崃市| 阿城市| 秀山| 栾川县| 东辽县| 靖远县| 岚皋县| 新宁县| 林口县| 武威市| 伊春市| 海丰县| 汾西县| 大埔县|