国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

外貿(mào)企業(yè)網(wǎng)站功能要求網(wǎng)店推廣的作用是

外貿(mào)企業(yè)網(wǎng)站功能要求,網(wǎng)店推廣的作用是,wordpress 目錄打不開,網(wǎng)站空間租賃??個(gè)人主頁:小羊 ??所屬專欄:Linux 很榮幸您能閱讀我的文章,誠請?jiān)u論指點(diǎn),歡迎歡迎 ~ 目錄 1、互斥鎖2、生產(chǎn)消費(fèi)模型2.1 阻塞隊(duì)列2.2 環(huán)形隊(duì)列 3、單例線程池4、線程安全和重入問題 1、互斥鎖 臨界資源:多線程…
頭像
??個(gè)人主頁:@小羊
??所屬專欄:Linux
很榮幸您能閱讀我的文章,誠請?jiān)u論指點(diǎn),歡迎歡迎 ~

動(dòng)圖描述

目錄

  • 1、互斥鎖
  • 2、生產(chǎn)消費(fèi)模型
    • 2.1 阻塞隊(duì)列
    • 2.2 環(huán)形隊(duì)列
  • 3、單例線程池
  • 4、線程安全和重入問題


1、互斥鎖

  • 臨界資源:多線程執(zhí)行流共享的資源就叫做臨界資源

  • 臨界區(qū):每個(gè)線程內(nèi)部,訪問臨界資源的代碼,就叫做臨界區(qū)

  • 互斥:任何時(shí)刻,互斥保證有且只有一個(gè)執(zhí)行流進(jìn)入臨界區(qū),訪問臨界資源,通常對(duì)臨界資源起保護(hù)作用

  • 原子性:不會(huì)被任何調(diào)度機(jī)制打斷的操作,該操作只有兩種狀態(tài),要么完成,要么未完成,沒有中間態(tài)

大部分情況,線程使用的數(shù)據(jù)都是局部變量,變量的地址空間在線程棧空間內(nèi),這種情況,變量歸屬單個(gè)線程,其他線程無法獲得這種變量。
但有時(shí)候,很多變量都需要在線程間共享,這樣的變量稱為共享變量,可以通過數(shù)據(jù)的共享,完成線程之間的交互。而多個(gè)線程并發(fā)的操作共享變量,會(huì)帶來一些問題。

在這里插入圖片描述

內(nèi)存中的數(shù)據(jù)是共享的,但是當(dāng)線程把數(shù)據(jù)從內(nèi)存讀到CPU中的寄存器中,變成線程的上下文數(shù)據(jù),就變成了私有的,而ticketnum--后需要把數(shù)據(jù)再次寫入到內(nèi)存中,如果線程在寫入內(nèi)存前被切換,多個(gè)線程都執(zhí)行這一操作就可能會(huì)出現(xiàn)ticketnum減為負(fù)數(shù)的情況。

避免類似上述問題,需要解決三個(gè)問題:

  1. 代碼必須要有互斥行為,當(dāng)代碼進(jìn)入臨界區(qū)時(shí),不允許其他線程進(jìn)入該臨界區(qū)。
  2. 如果多個(gè)線程同時(shí)要求執(zhí)行臨界區(qū)的代碼,并且臨界區(qū)沒有線程在執(zhí)行,那么只能允許一個(gè)線程進(jìn)入該臨界區(qū)。
  3. 如果線程不在臨界區(qū)中執(zhí)行,那么該線程不能阻止其他線程進(jìn)入臨界區(qū)。

要做到這三點(diǎn),本質(zhì)上就是需要一把鎖。Linux上提供的這把鎖叫互斥量。

| 線程或進(jìn)程什么時(shí)候被切換?

  1. 時(shí)間片耗盡時(shí)
  2. 有更高優(yōu)先級(jí)的進(jìn)程要調(diào)度時(shí)
  3. 通過sleep,從內(nèi)核返回用戶時(shí),會(huì)進(jìn)行時(shí)間片是否到達(dá)的檢測,進(jìn)而導(dǎo)致切換

在這里插入圖片描述

如果鎖對(duì)象是全局的或靜態(tài)的,可以用宏:PTHREAD_MUTEX_INITIALIZER初始化,并且不用我們主動(dòng)destroy;如果鎖對(duì)象是局部的,需要用pthread_mutex_init初始化,用pthread_mutex_destroy釋放。

  1. 所有對(duì)資源的保護(hù),都是對(duì)臨界區(qū)代碼的訪問,因?yàn)橘Y源都是通過代碼訪問的。
  2. 要保證加鎖的細(xì)粒度。
  3. 加鎖就是找到臨界區(qū),對(duì)臨界區(qū)進(jìn)行加鎖。

那么相應(yīng)的又有一些問題:

  • 鎖也是全局的共享資源,誰保證鎖的安全?加鎖和解鎖被設(shè)計(jì)為原子的。
  • 如果看待鎖?加鎖本質(zhì)就是對(duì)資源的預(yù)定工作,整體使用資源,所以加鎖前先要申請鎖。
  • 如果申請鎖的時(shí)候,鎖已經(jīng)被別的線程拿走了怎么辦?其他線程阻塞等待。
  • 線程在訪問臨界區(qū)的時(shí)候,可不可以被切換?可以,我被切走,其他線程也不能進(jìn)來,因?yàn)槲易叩臅r(shí)候是帶著鎖走的,保證了原子性。

lock是原子的,其他線程無法進(jìn)入,鎖是如何實(shí)現(xiàn)的?
為了實(shí)現(xiàn)互斥鎖操作,大多數(shù)體系結(jié)構(gòu)都提供了swap或exchange指令,該指令的作用是把寄存器和內(nèi)存單元的數(shù)據(jù)交換(私有和共享),由于只有一條指令,保證了原子性,即使是多處理器平臺(tái),訪問內(nèi)存的總線周期也有先后,一個(gè)處理器上的交換指令執(zhí)行時(shí)另一個(gè)處理器的交換指令只能等待總線周期。

#pragma once#include <iostream>
#include <pthread.h>namespace MutexModule
{class Mutex{public:Mutex(const Mutex&) = delete;const Mutex& operator=(const Mutex&) = delete;Mutex(){int n = pthread_mutex_init(&_lock, nullptr);}void Lock(){int n = pthread_mutex_lock(&_lock);}void Unlock(){int n = pthread_mutex_unlock(&_lock);}pthread_mutex_t* LockPtr(){return &_lock;}~Mutex(){int n = pthread_mutex_destroy(&_lock);}private:pthread_mutex_t _lock;};class LockGuard{public:LockGuard(Mutex& mutex):_mutex(mutex){_mutex.Lock();}~LockGuard(){_mutex.Unlock();}private:Mutex& _mutex;};
}

2、生產(chǎn)消費(fèi)模型

2.1 阻塞隊(duì)列

當(dāng)一個(gè)線程互斥地訪問某個(gè)變量時(shí),它可能發(fā)現(xiàn)在其他線程改變狀態(tài)之前,它什么都做不了。例如一個(gè)線程訪問隊(duì)列時(shí),發(fā)現(xiàn)隊(duì)列為空它只能等待,直到其他線程將一個(gè)節(jié)點(diǎn)添加到隊(duì)列中,這種情況就需要條件變量。

生產(chǎn)者消費(fèi)者模型:

  • 生產(chǎn)者和生產(chǎn)者:互斥
  • 消費(fèi)者和消費(fèi)者:互斥
  • 生產(chǎn)者和消費(fèi)者:互斥 && 同步

總結(jié):3種關(guān)系2種角色1個(gè)交易區(qū)。

在這里插入圖片描述

pthread_cond_wait是一個(gè)函數(shù),只要是函數(shù)就可能會(huì)出錯(cuò),如果這個(gè)函數(shù)調(diào)用出錯(cuò)繼續(xù)往下執(zhí)行代碼,但是當(dāng)前阻塞隊(duì)列中已經(jīng)滿了,再向其中放數(shù)據(jù)就出錯(cuò)了。還有如果阻塞等待的線程和其他線程所發(fā)的信號(hào)數(shù)量不匹配,也就是出現(xiàn)了偽喚醒,也會(huì)出現(xiàn)問題。
為了規(guī)避這種問題,這里判斷阻塞隊(duì)列是否為滿我們就不同if判斷了,而是改用while判斷,只要阻塞隊(duì)列為空,就一直阻塞等待,這樣做可以規(guī)避很多可能出現(xiàn)的錯(cuò)誤。

》:上面實(shí)現(xiàn)的生產(chǎn)者消費(fèi)者模型只是單生產(chǎn)單消費(fèi),只保證了生產(chǎn)者和消費(fèi)者之間的互斥關(guān)系,如果增加線程讓其變成多生產(chǎn)多消費(fèi),該如何修改?
事實(shí)上我們只需要增加對(duì)應(yīng)的線程即可,因?yàn)槲覀兊呐R界區(qū)只用了一把互斥鎖保護(hù),生產(chǎn)者和生產(chǎn)者之間,消費(fèi)者和消費(fèi)者之間也可以保證互斥的關(guān)系。

》:這里我們實(shí)現(xiàn)的生產(chǎn)者消費(fèi)者模型在訪問臨界區(qū)資源時(shí)是互斥的,不難發(fā)現(xiàn)它運(yùn)行的效率不是很高,那我們該怎么保證生產(chǎn)者消費(fèi)者模型的效率問題呢?
事實(shí)上我們看待生產(chǎn)者消費(fèi)者模型不能只聚焦于臨界區(qū)這小點(diǎn)來思考,為什么說是一小點(diǎn)呢?生產(chǎn)者要生產(chǎn)數(shù)據(jù)(實(shí)際上是往臨界區(qū)中放數(shù)據(jù)),也是需要從外部獲取“原料”的,消費(fèi)者消費(fèi)數(shù)據(jù)(實(shí)際上是從臨界區(qū)中取數(shù)據(jù)),拿到后也需要處理數(shù)據(jù),不管是生產(chǎn)者從別的地方獲取“原料”還是消費(fèi)者處理數(shù)據(jù),都是需要時(shí)間的。也就是說在生產(chǎn)者從外部獲取資源的時(shí)候,消費(fèi)者可以隨意訪問臨界區(qū),在消費(fèi)者處理數(shù)據(jù)的時(shí)候生產(chǎn)者也可以隨意訪問臨界區(qū),這個(gè)時(shí)候生產(chǎn)者和消費(fèi)者是并行的,也就是說只有生產(chǎn)者訪問臨界區(qū)相對(duì)于消費(fèi)者訪問臨界區(qū)是串行的,這是生產(chǎn)者消費(fèi)者模型高效率的關(guān)鍵。

#pragma once
#include <iostream>
#include <pthread.h>
#include <queue>
#include <unistd.h>
#include "Mutex.hpp"
#include "Cond.hpp"namespace BlockQueueModule
{// version 2using namespace CondModule;using namespace MutexModule;template<class T>class BlockQueue{private:bool IsFull() {return _cap == _q.size();}bool IsEmpty() {return _q.empty();}public:BlockQueue(int cap = 10):_cap(cap), _cwait(0), _pwait(0){}void Equeue(const T &data)   //生產(chǎn)者{LockGuard lockguard(_mutex);//RAIIwhile (IsFull()){std::cout << "生產(chǎn)者進(jìn)入等待..." << std::endl;_pwait++;//如果阻塞隊(duì)列為滿,則等待消費(fèi)者發(fā)信號(hào)//wait首先解鎖,讓其他線程有訪問臨界區(qū)的機(jī)會(huì)_producter_signal.Wait(_mutex);_pwait--;std::cout << "生產(chǎn)者被喚醒..." << std::endl;//wait被喚醒后重新申請鎖,訪問臨界區(qū)}//走到這里,說明生產(chǎn)者收到了消費(fèi)者發(fā)的信號(hào),臨界區(qū)一定有空位置,可以生產(chǎn)了_q.push(data);//生產(chǎn)者放完數(shù)據(jù),一定有數(shù)據(jù),給消費(fèi)者發(fā)信號(hào)可以消費(fèi)了if (_cwait){_consumer_signal.Notify();}}void Pop(T *data)         //消費(fèi)者{LockGuard lockguard(_mutex);//RAIIwhile (IsEmpty()){std::cout << "消費(fèi)者進(jìn)入等待..." << std::endl;_cwait++;//如果阻塞隊(duì)列為空,則等待生產(chǎn)者發(fā)信號(hào)_consumer_signal.Wait(_mutex);_cwait--;std::cout << "消費(fèi)者被喚醒..." << std::endl;}//走到這里,說明消費(fèi)者收到了生產(chǎn)者發(fā)的信號(hào),臨界區(qū)一定有數(shù)據(jù),可以消費(fèi)了*data = _q.front();_q.pop();//消費(fèi)者取完數(shù)據(jù),一定有空位置,給生產(chǎn)者發(fā)信號(hào)可以生成了if (_pwait){_producter_signal.Notify();}}~BlockQueue(){}private:std::queue<T> _q;                  //臨界資源int _cap;                          //默認(rèn)臨界區(qū)大小Mutex _mutex;                      //互斥鎖Cond _producter_signal;            //生產(chǎn)者條件變量Cond _consumer_signal;             //消費(fèi)者條件變量int _cwait;     //有多少個(gè)消費(fèi)者在阻塞等待int _pwait;     //有多少個(gè)生產(chǎn)者在阻塞等待};// version 1// static const int gcap = 10; //默認(rèn)臨界區(qū)大小// template<class T>// class BlockQueue// {// private://     bool IsFull()//     {//         return _cap == _q.size();//     }//     bool IsEmpty()//     {//         return _q.empty();//     }// public://     BlockQueue(int cap = gcap)//         :_cap(cap), _cwait(0), _pwait(0)//     {//         pthread_mutex_init(&_mutex, nullptr);//         pthread_cond_init(&_producter_signal, nullptr);//         pthread_cond_init(&_consumer_signal, nullptr);//     }//     void Equeue(const T &data)   //生產(chǎn)者//     {//         pthread_mutex_lock(&_mutex);//         while (IsFull())//         {//             std::cout << "生產(chǎn)者進(jìn)入等待..." << std::endl;//             _pwait++;//             //如果阻塞隊(duì)列為滿,則等待消費(fèi)者發(fā)信號(hào)//             //wait首先解鎖,讓其他線程有訪問臨界區(qū)的機(jī)會(huì)//             pthread_cond_wait(&_producter_signal, &_mutex);//             _pwait--;//             std::cout << "生產(chǎn)者被喚醒..." << std::endl;//             //wait被喚醒后重新申請鎖,訪問臨界區(qū)//         }//         //走到這里,說明生產(chǎn)者收到了消費(fèi)者發(fā)的信號(hào),臨界區(qū)一定有空位置,可以生產(chǎn)了//         _q.push(data);//         //生產(chǎn)者放完數(shù)據(jù),一定有數(shù)據(jù),給消費(fèi)者發(fā)信號(hào)可以消費(fèi)了//         if (_cwait)//         {//             pthread_cond_signal(&_consumer_signal);//         }//         pthread_mutex_unlock(&_mutex);//     }//     void Pop(T *data)         //消費(fèi)者//     {//         pthread_mutex_lock(&_mutex);//         while (IsEmpty())//         {//             std::cout << "消費(fèi)者進(jìn)入等待..." << std::endl;//             _cwait++;//             //如果阻塞隊(duì)列為空,則等待生產(chǎn)者發(fā)信號(hào)//             pthread_cond_wait(&_consumer_signal, &_mutex);//             _cwait--;//             std::cout << "消費(fèi)者被喚醒..." << std::endl;//         }//         //走到這里,說明消費(fèi)者收到了生產(chǎn)者發(fā)的信號(hào),臨界區(qū)一定有數(shù)據(jù),可以消費(fèi)了//         *data = _q.front();//         _q.pop();//         //消費(fèi)者取完數(shù)據(jù),一定有空位置,給生產(chǎn)者發(fā)信號(hào)可以生成了//         if (_pwait)//         {//             pthread_cond_signal(&_producter_signal);//         }//         pthread_mutex_unlock(&_mutex);//     }//     ~BlockQueue()//     {//         pthread_mutex_destroy(&_mutex);//         pthread_cond_destroy(&_producter_signal);//         pthread_cond_destroy(&_consumer_signal);//     }// private://     std::queue<T> _q;                  //臨界資源//     int _cap;                          //最大容量//     pthread_mutex_t _mutex;            //互斥鎖//     pthread_cond_t _producter_signal;  //生產(chǎn)者條件變量//     pthread_cond_t _consumer_signal;   //消費(fèi)者條件變量//     int _cwait;     //有多少個(gè)消費(fèi)者在阻塞等待//     int _pwait;     //有多少個(gè)生產(chǎn)者在阻塞等待// };
}

2.2 環(huán)形隊(duì)列

對(duì)于環(huán)形隊(duì)列,重要的一點(diǎn)是為空或?yàn)闈M,指針指向的是同一個(gè)位置。如果為空,保證生產(chǎn)者先原子性的生產(chǎn),如果為滿,保證消費(fèi)者原子性的先消費(fèi)。這里體現(xiàn)出互斥是通過信號(hào)量來實(shí)現(xiàn)的。
資源用信號(hào)量表示,任何人訪問臨界資源之前都必須先申請信號(hào)量,信號(hào)量表示資源的數(shù)目。資源分為空間資源和數(shù)據(jù)資源,對(duì)于生產(chǎn)者來說他關(guān)注的是空間資源,對(duì)于消費(fèi)者來說他關(guān)注的是數(shù)據(jù)資源。

》:前面的阻塞隊(duì)列中不管是生產(chǎn)還是消費(fèi)前都要先判斷,為什么環(huán)形隊(duì)列這里沒有判斷呢?
因?yàn)檫@里信號(hào)量本身就是表示資源數(shù)目,只要成功,就一定有,不需要判斷。

上面已經(jīng)基本實(shí)現(xiàn)了生產(chǎn)者和消費(fèi)者之間的同步和互斥關(guān)系,那么多生產(chǎn)多消費(fèi)中生產(chǎn)者和生產(chǎn)者,消費(fèi)者和消費(fèi)者之間的互斥關(guān)系如何保證呢?

事實(shí)上上面生產(chǎn)者和消費(fèi)者之間的同步和互斥關(guān)系是通過信號(hào)量來保證的,也就是說單生產(chǎn)和單消費(fèi)這里不需要互斥鎖,在這里互斥鎖我們只需要用來處理生產(chǎn)者和生產(chǎn)者,消費(fèi)者和消費(fèi)者之間的互斥關(guān)系就行。而我們知道環(huán)形隊(duì)列中讀寫位置各自只有一個(gè),所以多線程之間的生產(chǎn)和消費(fèi)最后還是單生產(chǎn)單消費(fèi)問題,所以我們只需要用兩把鎖,一把鎖守護(hù)生產(chǎn)權(quán)利,一把鎖守護(hù)消費(fèi)權(quán)利,讓多線程先競爭這把鎖,然后生產(chǎn)或消費(fèi)。

在這里插入圖片描述

》:如上,我們應(yīng)該在哪個(gè)位置加鎖更好一點(diǎn)呢?
首先不管在哪個(gè)位置加鎖,我們都能保證生產(chǎn)者之間,消費(fèi)者之間都是互斥的關(guān)系。其次,多個(gè)線程申請鎖不管最后誰是贏家,可以肯定的是贏家只有一個(gè),也就是說如果先讓多線程申請鎖,然后再有這個(gè)贏家申請信號(hào)量;而如果先讓多個(gè)線程申請信號(hào)量,信號(hào)量可以是多個(gè),所以最后贏家可能有多個(gè),然后再讓這些個(gè)線程去競爭鎖,在這些線程競爭鎖的同時(shí)其他沒申請到信號(hào)量的線程如果有信號(hào)量了也可以同時(shí)申請信號(hào)量,也就是可以達(dá)到并行。
這就好比看電影,如果在前面加鎖就像是我們先排隊(duì),然后在買票,一次只能進(jìn)去一個(gè)同學(xué);如果在后面加鎖就像是我們先買票,然后在排隊(duì)進(jìn)入,在買到票的同學(xué)排隊(duì)進(jìn)入放映廳的過程中后面來的同學(xué)都可以先去買票,很明顯第二種效率更高。

#pragma once#include <iostream>
#include <vector>
#include <unistd.h>
#include <pthread.h>
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Sem.hpp"namespace RingQueueModule
{using namespace MutexModule;using namespace CondModule;using namespace SemModule;template<class T>class RingQueue{public:RingQueue(int cap):_ring(cap), _cap(cap), _p_step(0),_c_step(0), _spacesem(cap), _datasem(0){}void Equeue(const T& data){// 1.LockGuard lockguard(_p_lock);//先申請信號(hào)量,在競爭鎖,效率更高_spacesem.P();LockGuard lockguard(_p_lock);_ring[_p_step++] = data;_p_step %= _cap;_datasem.V();}void Pop(T *out){_datasem.P();LockGuard lockguard(_c_lock);*out = _ring[_c_step++];_c_step %= _cap;_spacesem.V();  //釋放資源,信號(hào)量+1}~RingQueue(){}private:std::vector<T> _ring;    //臨界資源int _cap;                //臨界空間大小int _p_step;             //生產(chǎn)者位置int _c_step;             //消費(fèi)者位置Sem _spacesem;           //空間信號(hào)量Sem _datasem;            //數(shù)據(jù)信號(hào)量Mutex _p_lock;           Mutex _c_lock;};
}

3、單例線程池

在這里插入圖片描述

#pragma once#include <iostream>
#include <vector>
#include <queue>
#include <memory>
#include "Thread.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Log.hpp"// 懶漢模式線程池
namespace ThreadPoolModule
{using namespace ThreadModule;using namespace LogModule;using namespace CondModule;using namespace LogModule;using thread_t = std::shared_ptr<Thread>;const static int threadnum = 5;template <class T>class ThreadPool{private:bool IsEmpty(){return _taskq.empty();}// 處理任務(wù)void HandlerTask(std::string name){LOG(LogLevel::DEBUG) << "線程: " << name << ", 進(jìn)入HandlerTask...";while (true){T t;{LockGuard lockguard(_lock);     // 在任務(wù)隊(duì)列中拿任務(wù)需要加鎖保護(hù)while (IsEmpty() && _isrunning) // 只有任務(wù)隊(duì)列為空 && 線程池在運(yùn)行,線程才需要等待休眠{_wait_num++;_cond.Wait(_lock);_wait_num--;}if (IsEmpty() && !_isrunning) // 只有任務(wù)隊(duì)列為空 && 線程池退出,所有的線程才不需要等待break;t = _taskq.front();_taskq.pop();}t(name); // 線程有獨(dú)立棧,處理任務(wù)不需要被保護(hù)}LOG(LogLevel::INFO) << "線程:" << name << ",退出...";}ThreadPool(int num = threadnum): _num(num), _wait_num(0), _isrunning(false){for (int i = 0; i < _num; i++){// 非靜態(tài)成員函數(shù)取函數(shù)指針需要加&_threads.push_back(std::make_shared<Thread>(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1)));LOG(LogLevel::INFO) << "創(chuàng)建線程:" << _threads.back()->Name();}}public:// 不支持拷貝、賦值ThreadPool(const ThreadPool<T>&) = delete;const ThreadPool<T>& operator=(const ThreadPool<T>&) = delete;// 1.將構(gòu)造函數(shù)私有化,讓其不能在類外實(shí)例化對(duì)象,只能在類里面創(chuàng)建一個(gè)對(duì)象// 2.創(chuàng)建單例對(duì)象的函數(shù)設(shè)為靜態(tài)函數(shù),在類外通過指定類域的方式訪問這個(gè)靜態(tài)成員函數(shù),獲取單例對(duì)象// 3.因?yàn)闃?gòu)造函數(shù)被私有,類外不能創(chuàng)建對(duì)象,非靜態(tài)成員函數(shù)只能通過對(duì)象訪問,不能通過指定類域的方式訪問static ThreadPool<T> *GetInstance(){if (_instance == nullptr){LockGuard lockguard(_mtx);if (_instance == nullptr){LOG(LogLevel::INFO) << "單例首次被執(zhí)行,需要加載對(duì)象...";_instance = new ThreadPool<T>();}}return _instance;}void Equeue(const T &in){LockGuard lockguard(_lock);if (_isrunning){_taskq.push(in);if (_wait_num > 0){_cond.Notify();}}}void Start(){LockGuard lockguard(_lock);if (_isrunning)return;_isrunning = true;for (auto &threadptr : _threads){threadptr->Start();LOG(LogLevel::INFO) << "啟動(dòng)線程:" << threadptr->Name();}}void Wait(){for (auto &threadptr : _threads){threadptr->Join();LOG(LogLevel::INFO) << "回收線程:" << threadptr->Name();}}void Stop(){LockGuard lockguard(_lock);if (_isrunning){// 退出線程池必須保證// 1.不能再進(jìn)任務(wù)_isrunning = false;// 2.線程池內(nèi)的任務(wù)必須全部處理完// 3.讓線程自己退出(被喚醒)if (_wait_num > 0){_cond.NotifyAll(); // 將等待中的線程全部喚醒,如果有任務(wù)處理完剩余任務(wù),線程正?;厥?/span>}}}~ThreadPool(){}private:std::vector<thread_t> _threads; // 管理線程std::queue<T> _taskq;           // 管理任務(wù)int _num;                       // 線程個(gè)數(shù)int _wait_num;                  // 正在等待任務(wù)的線程個(gè)數(shù)Mutex _lock;Cond _cond;      // 等待任務(wù)bool _isrunning; // 線程池狀態(tài)static ThreadPool<T>* _instance; // 單例對(duì)象static Mutex _mtx;};template<class T>ThreadPool<T>* ThreadPool<T>::_instance = nullptr;template<class T>Mutex ThreadPool<T>::_mtx;
}

4、線程安全和重入問題

  • 線程安全:就是多個(gè)線程在訪問共享資源時(shí),能夠正確地執(zhí)行,不會(huì)相互干擾或破壞彼此的執(zhí)行結(jié)果。一般而言,多個(gè)線程并發(fā)同一段只有局部變量的代碼時(shí),不會(huì)出現(xiàn)不同的結(jié)果。但是對(duì)全局變量或者靜態(tài)變量進(jìn)行操作,并且沒有鎖保護(hù)的情況下,容易出現(xiàn)該問題。
  • 重入:同一個(gè)函數(shù)被不同的執(zhí)行流調(diào)用,當(dāng)前一個(gè)流程還沒有執(zhí)行完,就有其他的執(zhí)行流再次進(jìn)入,我們稱之為重入。一個(gè)函數(shù)在重入的情況下,運(yùn)行結(jié)果不會(huì)出現(xiàn)任何不同或者任何問題,則該函數(shù)被稱為可重入函數(shù),否則,是不可重入函數(shù)。

重入可以分為兩種情況:

  • 多線程重入函數(shù)
  • 信號(hào)導(dǎo)致一個(gè)執(zhí)行流重復(fù)進(jìn)入函數(shù)

| 可重入和線程安全的聯(lián)系:

  • 函數(shù)是可重入的,那就是線程安全的。
  • 函數(shù)是不可重入的,那就不能由多個(gè)線程使用,有可能引發(fā)線程安全問題。
  • 如果一個(gè)函數(shù)中有全局變量,那么這個(gè)函數(shù)既不是線程安全也不是可重入的。

| 可重入與線程安全區(qū)別:

  • 可重入函數(shù)是線程安全函數(shù)的一種。
  • 線程安全不一定是可重入的,而可重入函數(shù)則一定是線程安全的。
  • 如果將對(duì)臨界資源的訪問加上鎖,則這個(gè)函數(shù)是線程安全的,但如果這個(gè)重入函數(shù)有鎖還未釋放則會(huì)產(chǎn)生死鎖,因此是不可重入的。

本篇文章的分享就到這里了,如果您覺得在本文有所收獲,還請留下您的三連支持哦~

頭像
http://aloenet.com.cn/news/28873.html

相關(guān)文章:

  • 南通網(wǎng)站群建設(shè)網(wǎng)絡(luò)廣告電話
  • 臨淄網(wǎng)站推廣烏魯木齊seo
  • 正規(guī)品牌網(wǎng)站設(shè)計(jì)推薦seo網(wǎng)站優(yōu)化多少錢
  • 做網(wǎng)站優(yōu)化的弊端如何在百度上建立網(wǎng)站
  • 公司做網(wǎng)站可以用個(gè)人域名app拉新任務(wù)平臺(tái)
  • 濮陽做網(wǎng)站免費(fèi)推廣引流app
  • wordpress 外貿(mào)站網(wǎng)站建設(shè)怎么弄
  • 做家務(wù)的男人免費(fèi)觀看網(wǎng)站搭建網(wǎng)站平臺(tái)需要多少錢
  • 做賭博網(wǎng)站會(huì)被判多久上海搜索引擎優(yōu)化seo
  • 桂林遇龍河優(yōu)化大師有必要安裝嗎
  • 網(wǎng)站制作培訓(xùn)費(fèi)用seo和競價(jià)排名的區(qū)別
  • 要想瀏覽國外網(wǎng)站 應(yīng)該怎么做特色產(chǎn)品推廣方案
  • 免費(fèi)二級(jí)域名備案解析seo優(yōu)化診斷工具
  • 電腦買編程代碼做網(wǎng)站應(yīng)用下載app排行榜
  • 麗水做網(wǎng)站公司利于seo的建站系統(tǒng)有哪些
  • 舟山論壇網(wǎng)站建設(shè)公司怎么推廣網(wǎng)絡(luò)營銷
  • 可以做h5游戲的網(wǎng)站谷歌是如何運(yùn)營的
  • 做面包有哪些網(wǎng)站知乎快速優(yōu)化系統(tǒng)
  • 那個(gè)網(wǎng)站教做仙芋鮮企業(yè)網(wǎng)站建設(shè)的一般要素
  • 用第三方做網(wǎng)站北京seo包年
  • 說做網(wǎng)站被收債正規(guī)淘寶代運(yùn)營去哪里找
  • 簡約網(wǎng)站模板廣州seo優(yōu)化排名公司
  • 重慶seo整站優(yōu)化外包服務(wù)最新消息
  • 文網(wǎng)文網(wǎng)站建設(shè)2024年陽性最新癥狀
  • 網(wǎng)站建設(shè)友情鏈接怎樣交換chrome瀏覽器下載安卓手機(jī)
  • wordpress掃碼槍鄭州好的seo外包公司
  • 尋找大連網(wǎng)站建設(shè)站長統(tǒng)計(jì)app進(jìn)入網(wǎng)址
  • 深圳本地招聘網(wǎng)站百度 人工客服
  • 如何幫別人推廣賺錢桂林seo顧問
  • 重慶建站網(wǎng)絡(luò)公司百度seo排名培訓(xùn) 優(yōu)化