1. 程式人生 > >C++初學者筆記:std::thread,子執行緒阻塞主執行緒的問題

C++初學者筆記:std::thread,子執行緒阻塞主執行緒的問題

C++ 11 支援跨平臺執行緒啦,當然要嚐嚐鮮

之前用的各平臺執行緒實現方式都不一樣,換個平臺或者換個庫,使用方法就不一樣了

編輯了個小例子,本來以為很容易,誰知道也要撞撞牆。

#include <stdio.h>
#include <stdlib.h>
#include <iostream> // std::cout
#include <thread>   // std::thread
#include <memory>
#include <condition_variable>
#include <chrono>

using namespace std;

class Task_Base
{
 public:
 Task_Base();
 virtual ~Task_Base();
 virtual void svc();
 void active();
 void release();
private:
  shared_ptr<thread> m_pThread;
  condition_variable m_cond;
  mutex m_mutex;
  int m_run;
};

Task_Base::Task_Base():m_pThread(nullptr),m_run(1)
{}

Task_Base::~Task_Base()
{};

void Task_Base::active()
{
    if(nullptr == m_pThread)
    {
     cout << "In Active1" << endl;
     m_pThread = make_shared<thread>(Task_Base::svc,this);
     //m_pThread->join(); //啟動執行緒
    }
};

void Task_Base::release()
{
 unique_lock<mutex> ul(m_mutex);
    m_cond.notify_one();
}

void Task_Base::svc()
{
 int i = 0;
 cout << "svc" << endl;
    while(m_run)
    {
     {
         unique_lock<mutex> ul(m_mutex);
         m_cond.wait(ul);
     }
     cout << "Let's Go!!!!!<" << i++ << endl;
    }
};


int main(int argc, const char *argv[])
{

 Task_Base t1;
    t1.active();
    cout << "主執行緒為什麼被阻塞啦???" << endl;
    for(int i = 0; i < 10 ; i++)
    {
     this_thread::sleep_for(std::chrono::milliseconds(2000));
     cout << "release one" << endl;
     t1.release();
    }
    system("pause"); //主執行緒需要在此處阻塞,可以換用其它方法
    return EXIT_SUCCESS;
}  /* ----------  end of function main  ---------- */

這個例子僅僅是為了學習std::thread 和 shared_ptr,查閱了網上的一些帖子,誰知道執行結果竟然和自己的設計初衷不一至。問題描述如下:

設計意圖:

在主執行緒裡建立任務執行緒t1,啟動t1,實現主執行緒和子執行緒並行執行,

由主執行緒通過呼叫t1的relase方法釋放訊號量,達到執行緒間同步執行的效果。

出現問題:

根據眾多的網貼資料,啟動執行緒在active方法裡實現,核心程式碼

m_pThread = make_shared<thread>(Task_Base::svc,this);
m_pThread->join(); //啟動執行緒

實際執行時出現問題,子執行緒阻塞了主執行緒,主執行緒需要等待子執行緒執行完畢才能呼叫release方法,於是死鎖了

問題的關鍵就出在了

m_pThread->join(); //啟動執行緒

這一行上,其實線上程初始化時呼叫m_pThread = make_shared<thread>(Task_Base::svc,this) 時,子執行緒已經開始執行,

如果不需要子執行緒阻塞主執行緒,就不要呼叫join方法