成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

C++11多線程編程的示例分析

小編給大家分享一下C++11多線程編程的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

為湯旺等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及湯旺網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為網(wǎng)站建設(shè)、網(wǎng)站制作、湯旺網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

1.在C++11中創(chuàng)建新線程

在每個(gè)c++應(yīng)用程序中,都有一個(gè)默認(rèn)的主線程,即main函數(shù),在c++11中,我們可以通過(guò)創(chuàng)建std::thread類的對(duì)象來(lái)創(chuàng)建其他線程,每個(gè)std :: thread對(duì)象都可以與一個(gè)線程相關(guān)聯(lián),只需包含頭文件< thread>??梢允褂胹td :: thread對(duì)象附加一個(gè)回調(diào),當(dāng)這個(gè)新線程啟動(dòng)時(shí),它將被執(zhí)行。 這些回調(diào)可以為函數(shù)指針、函數(shù)對(duì)象、Lambda函數(shù)。
  線程對(duì)象可通過(guò)std::thread thObj(< CALLBACK>)來(lái)創(chuàng)建,新線程將在創(chuàng)建新對(duì)象后立即開(kāi)始,并且將與已啟動(dòng)的線程并行執(zhí)行傳遞的回調(diào)。此外,任何線程可以通過(guò)在該線程的對(duì)象上調(diào)用join()函數(shù)來(lái)等待另一個(gè)線程退出。
  使用函數(shù)指針創(chuàng)建線程:

//main.cpp
#include <iostream>
#include <thread>
void thread_function() {    
    for (int i = 0; i < 5; i++)        
    std::cout << "thread function excuting" << std::endl;
}int main() {    
    std::thread threadObj(thread_function);    
    for (int i = 0; i < 5; i++)        
    std::cout << "Display from MainThread" << std::endl;
   threadObj.join();    
   std::cout << "Exit of Main function" << std::endl;    return 0;
}

使用函數(shù)對(duì)象創(chuàng)建線程:

#include <iostream>
#include <thread>
class DisplayThread {
    public:void operator ()() {        
        for (int i = 0; i < 100; i++)            
        std::cout << "Display Thread Excecuting" << std::endl;
    }
};
int main() {    
    std::thread threadObj((DisplayThread()));    
    for (int i = 0; i < 100; i++)        
    std::cout << "Display From Main Thread " << std::endl;    
    std::cout << "Waiting For Thread to complete" << std::endl;
    threadObj.join();    
    std::cout << "Exiting from Main Thread" << std::endl;    
    return 0;
}

CmakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(Thread_test)set(CMAKE_CXX_STANDARD 11)
find_package(Threads REQUIRED)
add_executable(Thread_test main.cpp)
target_link_libraries(Thread_test ${CMAKE_THREAD_LIBS_INIT})

每個(gè)std::thread對(duì)象都有一個(gè)相關(guān)聯(lián)的id,std::thread::get_id() —-成員函數(shù)中給出對(duì)應(yīng)線程對(duì)象的id;
std::this_thread::get_id()—-給出當(dāng)前線程的id,如果std::thread對(duì)象沒(méi)有關(guān)聯(lián)的線程,get_id()將返回默認(rèn)構(gòu)造的std::thread::id對(duì)象:“not any thread”,std::thread::id也可以表示id。

2.joining和detaching 線程

線程一旦啟動(dòng),另一個(gè)線程可以通過(guò)調(diào)用std::thread對(duì)象上調(diào)用join()函數(shù)等待這個(gè)線程執(zhí)行完畢:

std::thread threadObj(funcPtr); 
threadObj.join();

例如,主線程啟動(dòng)10個(gè)線程,啟動(dòng)完畢后,main函數(shù)等待他們執(zhí)行完畢,join完所有線程后,main函數(shù)繼續(xù)執(zhí)行:

#include <iostream>
#include <thread>
#include <algorithm>
class WorkerThread
{
    public:void operator()(){        
        std::cout<<"Worker Thread "<<std::this_thread::get_id()<<"is Excecuting"<<std::endl;
    }
};
    int main(){    
        std::vector<std::thread> threadList;    
        for(int i = 0; i < 10; i++){
        threadList.push_back(std::thread(WorkerThread()));
    }    
    // Now wait for all the worker thread to finish i.e.
    // Call join() function on each of the std::thread object
    std::cout<<"Wait for all the worker thread to finish"<<std::endl;    
    std::for_each(threadList.begin(), threadList.end(), std::mem_fn(&std::thread::join));    
    std::cout<<"Exiting from Main Thread"<<std::endl;    
    return 0;
}

detach可以將線程與線程對(duì)象分離,讓線程作為后臺(tái)線程執(zhí)行,當(dāng)前線程也不會(huì)阻塞了.但是detach之后就無(wú)法在和線程發(fā)生聯(lián)系了.如果線程執(zhí)行函數(shù)使用了臨時(shí)變量可能會(huì)出現(xiàn)問(wèn)題,線程調(diào)用了detach在后臺(tái)運(yùn)行,臨時(shí)變量可能已經(jīng)銷毀,那么線程會(huì)訪問(wèn)已經(jīng)被銷毀的變量,需要在std::thread對(duì)象中調(diào)用std::detach()函數(shù):

std::thread threadObj(funcPtr)
threadObj.detach();

調(diào)用detach()后,std::thread對(duì)象不再與實(shí)際執(zhí)行線程相關(guān)聯(lián),在線程句柄上調(diào)用detach() 和 join()要小心.

3.將參數(shù)傳遞給線程

要將參數(shù)傳遞給線程的可關(guān)聯(lián)對(duì)象或函數(shù),只需將參數(shù)傳遞給std::thread構(gòu)造函數(shù),默認(rèn)情況下,所有的參數(shù)都將復(fù)制到新線程的內(nèi)部存儲(chǔ)中。
給線程傳遞參數(shù):

#include <iostream>
#include <string>
#include <thread>
void threadCallback(int x, std::string str) {  
    std::cout << "Passed Number = " << x << std::endl;  
    std::cout << "Passed String = " << str << std::endl;
}int main() {  
    int x = 10;  
    std::string str = "Sample String";  
    std::thread threadObj(threadCallback, x, str);
  threadObj.join();  
  return 0;
}

給線程傳遞引用:

#include <iostream>
#include <thread>
void threadCallback(int const& x) {  
    int& y = const_cast<int&>(x);
  y++;  
  std::cout << "Inside Thread x = " << x << std::endl;
}int main() {  
    int x = 9;  
    std::cout << "In Main Thread : Before Thread Start x = " << x << std::endl;  
    std::thread threadObj(threadCallback, x);
  threadObj.join();  
  std::cout << "In Main Thread : After Thread Joins x = " << x << std::endl;  
  return 0;
}

輸出結(jié)果為:
In Main Thread : Before Thread Start x = 9
Inside Thread x = 10
In Main Thread : After Thread Joins x = 9

Process finished with exit code 0
即使threadCallback接受參數(shù)作為引用,但是并沒(méi)有改變main中x的值,在線程引用外它是不可見(jiàn)的。這是因?yàn)榫€程函數(shù)threadCallback中的x是引用復(fù)制在新線程的堆棧中的臨時(shí)值,使用std::ref可進(jìn)行修改:

#include <iostream>
#include <thread>
void threadCallback(int const& x) {  
    int& y = const_cast<int&>(x);
  y++;  
  std::cout << "Inside Thread x = " << x << std::endl;
}int main() {  
    int x = 9;  std::cout << "In Main Thread : Before Thread Start x = " << x << std::endl;  
    std::thread threadObj(threadCallback, std::ref(x));
  threadObj.join();  
  std::cout << "In Main Thread : After Thread Joins x = " << x << std::endl;  
  return 0;
}

輸出結(jié)果為:
In Main Thread : Before Thread Start x = 9
Inside Thread x = 10
In Main Thread : After Thread Joins x = 10

Process finished with exit code 0
指定一個(gè)類的成員函數(shù)的指針作為線程函數(shù),將指針傳遞給成員函數(shù)作為回調(diào)函數(shù),并將指針指向?qū)ο笞鳛榈诙€(gè)參數(shù):

#include <iostream>
#include <thread>
class DummyClass { 
public:
  DummyClass() { }
  DummyClass(const DummyClass& obj) { }  
  void sampleMemberfunction(int x) {    
      std::cout << "Inside sampleMemberfunction " << x << std::endl;
  }
};
    int main() {
      DummyClass dummyObj;  
      int x = 10;  
      std::thread threadObj(&DummyClass::sampleMemberfunction, &dummyObj, x);
      threadObj.join();  
      return 0;
}

4.線程間數(shù)據(jù)的共享與競(jìng)爭(zhēng)條件

在多線程間的數(shù)據(jù)共享很簡(jiǎn)單,但是在程序中的這種數(shù)據(jù)共享可能會(huì)引起問(wèn)題,其中一種便是競(jìng)爭(zhēng)條件。當(dāng)兩個(gè)或多個(gè)線程并行執(zhí)行一組操作,訪問(wèn)相同的內(nèi)存位置,此時(shí),它們中的一個(gè)或多個(gè)線程會(huì)修改內(nèi)存位置中的數(shù)據(jù),這可能會(huì)導(dǎo)致一些意外的結(jié)果,這就是競(jìng)爭(zhēng)條件。競(jìng)爭(zhēng)條件通常較難發(fā)現(xiàn)并重現(xiàn),因?yàn)樗鼈儾⒉豢偸浅霈F(xiàn),只有當(dāng)兩個(gè)或多個(gè)線程執(zhí)行操作的相對(duì)順序?qū)е乱馔饨Y(jié)果時(shí),它們才會(huì)發(fā)生。
例如創(chuàng)建5個(gè)線程,這些線程共享類Wallet的一個(gè)對(duì)象,使用addMoney()成員函數(shù)并行添加100元。所以,如果最初錢(qián)包中的錢(qián)是0,那么在所有線程的競(jìng)爭(zhēng)執(zhí)行完畢后,錢(qián)包中的錢(qián)應(yīng)該是500,但是,由于所有線程同時(shí)修改共享數(shù)據(jù),在某些情況下,錢(qián)包中的錢(qián)可能遠(yuǎn)小于500。
測(cè)試如下:

#include <iostream>
#include <thread>
#include <algorithm>
class Wallet {    
    int mMoney;
    public: Wallet() : mMoney(0) { }    
    int getMoney() { return mMoney; }    
    void addMoney(int money) {        
        for (int i = 0; i < money; i++) {
            mMoney++;
        }
    }
};int testMultithreadWallet() {
    Wallet walletObject;    
    std::vector<std::thread> threads;    
    for (int i = 0; i < 5; i++) {
        threads.push_back(std::thread(&Wallet::addMoney, &walletObject, 100));
    }    for (int i = 0; i < 5; i++) {
        threads.at(i).join();
    }    
    return walletObject.getMoney();
}int main() {    
        int val = 0;    
        for (int k = 0; k < 100; k++) {        
        if ((val=testMultithreadWallet()) != 500) {            
            std::cout << "Error at count = " << k << " Money in Wallet = " << val << std::endl;
        }
    }    
    return 0;
}

每個(gè)線程并行地增加相同的成員變量“mMoney”,看似是一條線,但是這個(gè)“nMoney++”實(shí)際上被轉(zhuǎn)換為3條機(jī)器命令:
·在Register中加載”mMoney”變量
·增加register的值
·用register的值更新“mMoney”變量
在這種情況下,一個(gè)增量將被忽略,因?yàn)椴皇窃黾觤Money變量,而是增加不同的寄存器,“mMoney”變量的值被覆蓋。

5.使用mutex處理競(jìng)爭(zhēng)條件

為了處理多線程環(huán)境中的競(jìng)爭(zhēng)條件,我們需要mutex互斥鎖,在修改或讀取共享數(shù)據(jù)前,需要對(duì)數(shù)據(jù)加鎖,修改完成后,對(duì)數(shù)據(jù)進(jìn)行解鎖。在c++11的線程庫(kù)中,mutexes在< mutexe >頭文件中,表示互斥體的類是std::mutex。
就上面的問(wèn)題進(jìn)行處理,Wallet類提供了在Wallet中增加money的方法,并且在不同的線程中使用相同的Wallet對(duì)象,所以我們需要對(duì)Wallet的addMoney()方法加鎖。在增加Wallet中的money前加鎖,并且在離開(kāi)該函數(shù)前解鎖,看代碼:Wallet類內(nèi)部維護(hù)money,并提供函數(shù)addMoney(),這個(gè)成員函數(shù)首先獲取一個(gè)鎖,然后給wallet對(duì)象的money增加指定的數(shù)額,最后釋放鎖。

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
class Wallet {    
        int mMoney;    
        std::mutex mutex;public:
    Wallet() : mMoney(0) { }    
    int getMoney() { return mMoney;}    
    void addMoney(int money) {
        mutex.lock();        
        for (int i = 0; i < money; i++) {
            mMoney++;
        }
        mutex.unlock();
    }
};int testMultithreadWallet() {
    Wallet walletObject;    
    std::vector<std::thread> threads;    
    for (int i = 0; i < 5; ++i) {
        threads.push_back(std::thread(&Wallet::addMoney, &walletObject, 1000));
    }    for (int i = 0; i < threads.size(); i++) {
        threads.at(i).join();
    }    
    return walletObject.getMoney();
}int main() {    
        int val = 0;    
        for (int k = 0; k < 1000; k++) {        
        if ((val = testMultithreadWallet()) != 5000) {            
        std::cout << "Error at count= " << k << " money in wallet" << val << std::endl;
        }
    }    
    return 0;
}

這種情況保證了錢(qián)包里的錢(qián)不會(huì)出現(xiàn)少于5000的情況,因?yàn)閍ddMoney()中的互斥鎖確保了只有在一個(gè)線程修改完成money后,另一個(gè)線程才能對(duì)其進(jìn)行修改,但是,如果我們忘記在函數(shù)結(jié)束后對(duì)鎖進(jìn)行釋放會(huì)怎么樣?這種情況下,一個(gè)線程將退出而不釋放鎖,其他線程將保持等待,為了避免這種情況,我們應(yīng)當(dāng)使用std::lock_guard,這是一個(gè)template class,它為mutex實(shí)現(xiàn)RALL,它將mutex包裹在其對(duì)象內(nèi),并將附加的mutex鎖定在其構(gòu)造函數(shù)中,當(dāng)其析構(gòu)函數(shù)被調(diào)用時(shí),它將釋放互斥體。

class Wallet {  
    int mMoney;  
    std::mutex mutex; public:
  Wallet() : mMoney(0) { }  int getMoney() { return mMoney;}  
  void addMoney(int money) {    
  std::lock_guard<std::mutex> lockGuard(mutex);    
  for (int i = 0; i < mMoney; ++i) {      
  //如果在此處發(fā)生異常,lockGuadr的析構(gòu)函數(shù)將會(huì)因?yàn)槎褩U归_(kāi)而被調(diào)用
      mMoney++;      
      //一旦函數(shù)退出,那么lockGuard對(duì)象的析構(gòu)函數(shù)將被調(diào)用,在析構(gòu)函數(shù)中mutex會(huì)被釋放
    }

  }
};

6.條件變量

條件變量是一種用于在2個(gè)線程之間進(jìn)行信令的事件,一個(gè)線程可以等待它得到信號(hào),其他的線程可以給它發(fā)信號(hào)。在c++11中,條件變量需要頭文件< condition_variable>,同時(shí),條件變量還需要一個(gè)mutex鎖。
條件變量是如何運(yùn)行的:
·線程1調(diào)用等待條件變量,內(nèi)部獲取mutex互斥鎖并檢查是否滿足條件;
·如果沒(méi)有,則釋放鎖,并等待條件變量得到發(fā)出的信號(hào)(線程被阻塞),條件變量的wait()函數(shù)以原子方式提供這兩個(gè)操作;
·另一個(gè)線程,如線程2,當(dāng)滿足條件時(shí),向條件變量發(fā)信號(hào);
·一旦線程1正等待其恢復(fù)的條件變量發(fā)出信號(hào),線程1便獲取互斥鎖,并檢查與條件變量相關(guān)關(guān)聯(lián)的條件是否滿足,或者是否是一個(gè)上級(jí)調(diào)用,如果多個(gè)線程正在等待,那么notify_one將只解鎖一個(gè)線程;
·如果是一個(gè)上級(jí)調(diào)用,那么它再次調(diào)用wait()函數(shù)。
條件變量的主要成員函數(shù):
Wait()
它使得當(dāng)前線程阻塞,直到條件變量得到信號(hào)或發(fā)生虛假喚醒;
它原子性地釋放附加的mutex,阻塞當(dāng)前線程,并將其添加到等待當(dāng)前條件變量對(duì)象的線程列表中,當(dāng)某線程在同樣的條件變量上調(diào)用notify_one() 或者 notify_all(),線程將被解除阻塞;
這種行為也可能是虛假的,因此,解除阻塞后,需要再次檢查條件;
一個(gè)回調(diào)函數(shù)會(huì)傳給該函數(shù),調(diào)用它來(lái)檢查其是否是虛假調(diào)用,還是確實(shí)滿足了真實(shí)條件;
當(dāng)線程解除阻塞后,wait()函數(shù)獲取mutex鎖,并檢查條件是否滿足,如果條件不滿足,則再次原子性地釋放附加的mutex,阻塞當(dāng)前線程,并將其添加到等待當(dāng)前條件變量對(duì)象的線程列表中。
notify_one()
如果所有線程都在等待相同的條件變量對(duì)象,那么notify_one會(huì)取消阻塞其中一個(gè)等待線程。
notify_all()
如果所有線程都在等待相同的條件變量對(duì)象,那么notify_all會(huì)取消阻塞所有的等待線程。

#include <iostream>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
using namespace std::placeholders;
class Application {    
    std::mutex m_mutex;    
    std::condition_variable m_condVar;    
    bool m_bDataLoaded;public:
  Application() {
        m_bDataLoaded = false;
    }    
    void loadData() {        
            //使該線程sleep 1秒
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));        
        std::cout << "Loading Data from XML" << std::endl;        //鎖定數(shù)據(jù)
        std::lock_guard<std::mutex> guard(m_mutex);        //flag設(shè)為true,表明數(shù)據(jù)已加載
        m_bDataLoaded = true;        //通知條件變量
        m_condVar.notify_one();
    }    bool isDataLoaded() {        
             return m_bDataLoaded;
    }    void mainTask() {        
            std::cout << "Do some handshaking" << std::endl;        //獲取鎖
        std::unique_lock<std::mutex> mlock(m_mutex);        //開(kāi)始等待條件變量得到信號(hào)
        //wait()將在內(nèi)部釋放鎖,并使線程阻塞
        //一旦條件變量發(fā)出信號(hào),則恢復(fù)線程并再次獲取鎖
        //然后檢測(cè)條件是否滿足,如果條件滿足,則繼續(xù),否則再次進(jìn)入wait
        m_condVar.wait(mlock, std::bind(&Application::isDataLoaded, this));        
        std::cout << "Do Processing On loaded Data" << std::endl;
    }
};int main() {
    Application app;    
    std::thread thread_1(&Application::mainTask, &app);    
    std::thread thread_2(&Application::loadData, &app);
    thread_2.join();
    thread_1.join();    return 0;
}

以上是“C++11多線程編程的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!

標(biāo)題名稱:C++11多線程編程的示例分析
當(dāng)前網(wǎng)址:http://jinyejixie.com/article28/jjiocp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、、網(wǎng)站維護(hù)、移動(dòng)網(wǎng)站建設(shè)商城網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

小程序開(kāi)發(fā)
华池县| 宁河县| 金阳县| 彭山县| 普宁市| 库伦旗| 开封县| 应城市| 罗山县| 汕尾市| 宜川县| 开封县| 衢州市| 永年县| 扎赉特旗| 玉树县| 阳春市| 阿拉尔市| 乐至县| 右玉县| 门头沟区| 柞水县| 长岛县| 通河县| 连平县| 资中县| 班玛县| 呼和浩特市| 北川| 东城区| 河曲县| 怀来县| 阿拉善右旗| 昂仁县| 松潘县| 鹿邑县| 同江市| 中西区| 崇州市| 宜城市| 镇赉县|