最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Linux線程互斥之線程加鎖的使用詳解

 更新時(shí)間:2025年04月29日 09:54:44   作者:s_little_monster_  
這篇文章主要介紹了Linux線程互斥之線程加鎖的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

一、鎖的定義

線程加鎖是在多線程編程環(huán)境中,為了確保在同一時(shí)刻只有一個(gè)線程能夠訪問(wèn)特定的共享資源或執(zhí)行特定的代碼段,而采取的一種同步手段,通過(guò)在需要保護(hù)的資源或代碼段前獲取鎖,在訪問(wèn)完成后釋放鎖,來(lái)實(shí)現(xiàn)對(duì)共享資源的互斥訪問(wèn)

二、庫(kù)函數(shù)

1、初始化互斥鎖

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
  • 返回值:成功返回0,失敗返回非零錯(cuò)誤碼
  • mutex:表示要初始化的互斥鎖,pthread_mutex_t是POSIX線程庫(kù)中定義的互斥鎖類型
  • attr:包含互斥鎖的屬性,設(shè)置為NULL表示使用默認(rèn)屬性

2、銷毀互斥鎖

#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
  • 返回值:成功返回0,失敗返回非零錯(cuò)誤碼
  • mutex:表示要銷毀的互斥鎖

3、加鎖

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
  • 返回值:成功返回0,失敗返回非零錯(cuò)誤碼
  • mutex:表示要加鎖的互斥鎖

4、解鎖

#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
  • 返回值:成功返回0,失敗返回非零錯(cuò)誤碼
  • mutex:表示要解鎖的互斥鎖

5、示例

#include <iostream>
#include <pthread.h>
#include <vector>
#include <cstdio>
#include <unistd.h>

using namespace std;

//定義一個(gè)全局鎖就可以不需要初始化和銷毀鎖的函數(shù)了
//pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

#define NUM 4
//共500張票
int tickets = 500;

class ThreadInfo
{
public:
    ThreadInfo(const string &threadname, pthread_mutex_t *lock)
    :threadname_(threadname)
    ,lock_(lock)
    {}

public:
    string threadname_;
    pthread_mutex_t *lock_;
};

void *GrabTickets(void *args)
{
    ThreadInfo *ti = static_cast<ThreadInfo*>(args);
    string name(ti->threadname_);
    while(true)
    {
        pthread_mutex_lock(ti->lock_); // 加鎖
        if(tickets > 0)
        {
            usleep(10000);
            printf("%s get a ticket: %d\n", name.c_str(), tickets);
            tickets--;
            pthread_mutex_unlock(ti->lock_); // 解鎖
        }
        else 
        {
            pthread_mutex_unlock(ti->lock_); // 解鎖
            break;
        }
        //這里上面的代碼
        usleep(13); // 用休眠來(lái)模擬搶到票的后續(xù)動(dòng)作
    }
    printf("%s quit...\n", name.c_str());
}

int main()
{
    pthread_mutex_t lock; // 定義互斥鎖
    pthread_mutex_init(&lock, nullptr); // 初始化互斥鎖
    vector<pthread_t> tids;
    vector<ThreadInfo*> tis;
    for(int i = 1; i <= NUM; i++)
    {
        pthread_t tid;
        ThreadInfo *ti = new ThreadInfo("Thread-"+to_string(i), &lock);
        pthread_create(&tid, nullptr, GrabTickets, ti);
        tids.push_back(tid);
        tis.push_back(ti);
    }

    // 等待所有線程
    for(auto tid : tids)
    {
        pthread_join(tid, nullptr);
    }
    // 釋放資源
    for(auto ti : tis)
    {
        delete ti;
    }
	// 銷毀互斥鎖
    pthread_mutex_destroy(&lock); 
    
    return 0;
}

這樣就不會(huì)出現(xiàn)好多線程搶到一張票或者搶到不存在的票的問(wèn)題了

三、深入理解鎖

1、解讀鎖的機(jī)制

(一)先入為主原則

我們將上方代碼中表示搶到票后續(xù)動(dòng)作的休眠代碼注釋掉再次執(zhí)行程序我們會(huì)發(fā)現(xiàn),都是線程1搶的票,多次執(zhí)行代碼之后發(fā)現(xiàn)這是概率性問(wèn)題,但是在搶票的時(shí)候,有一段時(shí)間的票都是一個(gè)線程搶到的,我們預(yù)想的應(yīng)該是幾乎平均分配的樣子

這說(shuō)明了幾個(gè)問(wèn)題:

  • 第一,線程對(duì)于鎖的競(jìng)爭(zhēng)能力不同,一定有一個(gè)首先搶到鎖的線程
  • 第二,一般來(lái)說(shuō),剛解鎖再去搶鎖的更容易一些,類似于上面的結(jié)果,一直是線程1在搶票

(二)鎖和線程

  • 對(duì)于上面第二個(gè)問(wèn)題來(lái)說(shuō),我們有處理方法,這種方法就是同步,同步可以讓所有的線程按照一定的順序獲取鎖
  • 對(duì)于其他線程來(lái)講,一個(gè)線程要么獲取到了鎖,要么釋放了鎖,當(dāng)前進(jìn)程訪問(wèn)臨界區(qū)的過(guò)程對(duì)于其他線程是原子的

在加鎖期間,即解鎖之前,是可以發(fā)生線程切換的,線程切換的時(shí)候是拿著鎖走的,被鎖起來(lái)的內(nèi)容其他線程也是訪問(wèn)不到臨界區(qū)的的,在該線程再次切換回來(lái)的時(shí)候,恢復(fù)線程上下文繼續(xù)訪問(wèn)臨界區(qū)代碼

(三)鎖的特點(diǎn)

加鎖的本質(zhì)就是用時(shí)間來(lái)?yè)Q取安全,我們知道在加鎖后,臨界區(qū)的代碼只能由一個(gè)線程執(zhí)行,如果是并發(fā)執(zhí)行,至少時(shí)間要縮短5倍,但是鎖給我們消除了安全隱患,即可能出現(xiàn)的++、--的隱患

加鎖的表現(xiàn)就是線程對(duì)于臨界區(qū)代碼串行執(zhí)行,一條線從上到下

我們加鎖的原則就是盡量保證臨界區(qū)的代碼要少一些,可以使單線程執(zhí)行的代碼量更小,多線程綜合處理的代碼量更大,提高效率

鎖的本身是共享資源,所以加鎖和解鎖本身就被設(shè)計(jì)成為了原子性操作(加鎖和解鎖通過(guò)硬件提供的原子指令,結(jié)合操作系統(tǒng)內(nèi)核態(tài)的底層同步原語(yǔ)支持以及庫(kù)層面的合理封裝,來(lái)確保操作的原子性),這樣可以確保在多線程環(huán)境下對(duì)共享資源加鎖和解鎖操作的完整性與一致性,避免因多線程并發(fā)干擾導(dǎo)致鎖狀態(tài)異常,進(jìn)而保障線程安全和數(shù)據(jù)的正確性

2、鎖的原理

下面來(lái)看一下加鎖解鎖對(duì)應(yīng)的匯編指令,我們說(shuō),一條匯編指令就是原子性的

首先al寄存器中的數(shù)字為0時(shí),代表鎖已被拿走,為非零(一般為1)時(shí),代表鎖當(dāng)前空閑,可以上鎖

加鎖機(jī)制

  • movb $0, %al:將值 0 移動(dòng)到 AL 寄存器
  • xchgb %al, mutex:這是一個(gè)原子交換指令,將 AL 寄存器中的值(即 0)與 mutex 變量的值交換
  • if (al寄存器的內(nèi)容 > 0):檢查 AL 寄存器中的內(nèi)容(此時(shí)它保存的是原來(lái) mutex 的值),如果值大于 0,說(shuō)明互斥鎖之前沒(méi)有被鎖定,鎖定成功,返回 0
  • else:如果 AL 中的值是 0,說(shuō)明互斥鎖已經(jīng)被鎖定,程序會(huì)等待
  • goto lock:程序跳轉(zhuǎn)回 lock 標(biāo)簽,重新嘗試獲取鎖

解鎖機(jī)制

  • movb $1, mutex:將值 1 移動(dòng)到 mutex
  • xchgb %al, mutex:通過(guò)交換 AL 中的值和 mutex,實(shí)現(xiàn)解鎖
  • return 0:解鎖后,函數(shù)返回

四、鎖的封裝

1、LockGuard.hpp

#pragma once
#include <pthread.h>
//簡(jiǎn)單的封裝了一下函數(shù),用的時(shí)候方便一些
class Mutex
{
public:
    Mutex(pthread_mutex_t *lock)
    :lock_(lock)
    {}

    void Lock()
    {
        pthread_mutex_lock(lock_);
    }

    void Unlock()
    {
        pthread_mutex_unlock(lock_);
    }
private:
    pthread_mutex_t *lock_;
};

class LockGuard
{
public:
    LockGuard(pthread_mutex_t *lock)
    :mutex_(lock)
    {
        mutex_.Lock(); // 對(duì)象創(chuàng)建的時(shí)候加鎖
    }

    ~LockGuard()
    {
        mutex_.Unlock(); // 對(duì)象銷毀的時(shí)候解鎖
    }
private:
    Mutex mutex_;
};
#include <iostream>
#include <pthread.h>
#include <vector>
#include <cstdio>
#include <unistd.h>
#include "LockGuard.hpp"

using namespace std;

#define NUM 4

int tickets = 500; 
//全局變量定義鎖
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

class ThreadInfo
{
public:
    ThreadInfo(const string &threadname)
        : threadname_(threadname)

public:
    string threadname_;
};

void *GrabTickets(void *args)
{
    ThreadInfo *ti = static_cast<ThreadInfo *>(args);
    string name(ti->threadname_);
    while (true)
    {
        {
            LockGuard lockguard(&lock); // RAII 風(fēng)格的鎖
            if (tickets > 0)
            {
                usleep(10000);
                printf("%s get a ticket: %d\n", name.c_str(), tickets);
                tickets--;
            }
            else
            {
                break;
            }
        }
        usleep(13); // 用休眠來(lái)模擬搶到票的后續(xù)動(dòng)作
    }

    printf("%s quit...\n", name.c_str());
}

int main()
{
    vector<pthread_t> tids;
    vector<ThreadInfo *> tis;
    for (int i = 1; i <= NUM; i++)
    {
        pthread_t tid;
        ThreadInfo *ti = new ThreadInfo("Thread-" + to_string(i));
        pthread_create(&tid, nullptr, GrabTickets, ti);
        tids.push_back(tid);
        tis.push_back(ti);
    }

    // 等待所有線程
    for (auto tid : tids)
    {
        pthread_join(tid, nullptr);
    }

    // 釋放資源
    for (auto ti : tis)
    {
        delete ti;
    }

    pthread_mutex_destroy(&lock);
    return 0;
}

這里封裝的鎖是RAII風(fēng)格的鎖,RAII風(fēng)格是一種在 C++ 等編程語(yǔ)言中利用對(duì)象的構(gòu)造和析構(gòu)函數(shù)來(lái)自動(dòng)管理資源的技術(shù),確保資源在對(duì)象創(chuàng)建時(shí)獲取,在對(duì)象生命周期結(jié)束時(shí)自動(dòng)釋放,以防止資源泄漏并簡(jiǎn)化資源管理

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • linux中使用grep命令詳解

    linux中使用grep命令詳解

    在本篇文章里小編給大家整理了關(guān)于linux中使用grep命令的相關(guān)知識(shí)點(diǎn)內(nèi)容,需要的朋友們跟著學(xué)習(xí)下。
    2019-03-03
  • linux服務(wù)器下通過(guò)iptables+Denyhost抵御暴力破解的配置方法

    linux服務(wù)器下通過(guò)iptables+Denyhost抵御暴力破解的配置方法

    這篇文章主要介紹了linux服務(wù)器下通過(guò)iptables + Denyhost抵御暴力破解的方法,需要的朋友可以參考下
    2014-11-11
  • 記一次Ubuntu服務(wù)器被黑經(jīng)歷

    記一次Ubuntu服務(wù)器被黑經(jīng)歷

    最近我們的一臺(tái)Ubuntu阿里云服務(wù)器一直提示有肉雞行為,提示了好幾天,開始并沒(méi)有關(guān)注,然后連續(xù)幾天后發(fā)現(xiàn)應(yīng)該是個(gè)大問(wèn)題啊,很可能服務(wù)被侵入了。下面通過(guò)本文給大家分享下詳情
    2016-11-11
  • CentOS 7 在vmware中的網(wǎng)絡(luò)設(shè)置詳細(xì)介紹

    CentOS 7 在vmware中的網(wǎng)絡(luò)設(shè)置詳細(xì)介紹

    這篇文章主要介紹了CentOS 7 在vmware中的網(wǎng)絡(luò)設(shè)置詳細(xì)介紹的相關(guān)資料,這里對(duì)主要網(wǎng)絡(luò)問(wèn)題進(jìn)行了一一介紹及如何解決,需要的朋友可以參考下
    2016-11-11
  • linux設(shè)置tomcat開機(jī)啟動(dòng)方式

    linux設(shè)置tomcat開機(jī)啟動(dòng)方式

    本文介紹了在Linux系統(tǒng)中配置Tomcat開機(jī)自啟動(dòng)的方法,包括創(chuàng)建systemd服務(wù)文件、重新加載系統(tǒng)管理器配置、啟用服務(wù)等步驟,并說(shuō)明了如何指定JDK和配置日志保留期限
    2026-03-03
  • Linux-Redhat系統(tǒng)啟動(dòng)讀取文件方式

    Linux-Redhat系統(tǒng)啟動(dòng)讀取文件方式

    文章詳細(xì)描述了RHEL系統(tǒng)從啟動(dòng)到登錄的整個(gè)過(guò)程,包括讀取關(guān)鍵配置文件、加載內(nèi)核、掛載文件系統(tǒng)、啟動(dòng)初始化系統(tǒng)以及進(jìn)入用戶界面的步驟
    2026-02-02
  • 使用CDN之后APACHE日志記錄中IP地址不正確的解決方案

    使用CDN之后APACHE日志記錄中IP地址不正確的解決方案

    這篇文章主要介紹了使用CDN之后APACHE日志記錄中IP地址不正確的解決方案,需要的朋友可以參考下
    2014-12-12
  • Linux中使用Cron定時(shí)執(zhí)行SQL任務(wù)的實(shí)現(xiàn)步驟

    Linux中使用Cron定時(shí)執(zhí)行SQL任務(wù)的實(shí)現(xiàn)步驟

    在Linux系統(tǒng)中,計(jì)劃任務(wù)(Cron)是一種強(qiáng)大的工具,可以自動(dòng)執(zhí)行預(yù)定的任務(wù),它非常適合定期運(yùn)行腳本、備份數(shù)據(jù)、清理臨時(shí)文件等一系列重復(fù)性任務(wù),本文給大家介紹了如何在Linux中使用Cron定時(shí)執(zhí)行SQL任務(wù),需要的朋友可以參考下
    2024-11-11
  • Linux中crontab定時(shí)任務(wù)不執(zhí)行的原因

    Linux中crontab定時(shí)任務(wù)不執(zhí)行的原因

    本篇文章主要介紹了Linux中crontab定時(shí)任務(wù)不執(zhí)行的原因,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • 如何理解與識(shí)別Linux中的文件類型

    如何理解與識(shí)別Linux中的文件類型

    這篇文章主要給大家介紹了關(guān)于如何理解與識(shí)別Linux中文件類型的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Linux系統(tǒng)具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評(píng)論

任丘市| 台南县| 牡丹江市| 荃湾区| 环江| 越西县| 蕉岭县| 绩溪县| 如东县| 交口县| 万宁市| 牡丹江市| 金平| 莱阳市| 邢台县| 柘荣县| 赤城县| 什邡市| 西乌珠穆沁旗| 罗田县| 沙湾县| 平阴县| 永登县| 建始县| 文水县| 罗源县| 修武县| 通山县| 阳东县| 闽侯县| 乾安县| 西藏| 扎鲁特旗| 辽中县| 丰台区| 望江县| 清河县| 加查县| 丰城市| 晋江市| 皮山县|