2016-12-05 49 views
0

我寫了這個示例程序來模仿我試圖在一個更大的程序中做什麼。線程與原子和互斥類的內部類

我有一些數據會來自用戶,並被傳遞到一個線程進行一些處理。我正在使用數據周圍的互斥標記來標記有數據時的信號。

使用lambda表達式,是指向*發送到線程的指針嗎?我似乎正在得到我期望在cout聲明中的行爲。

互斥數據是否正確使用了數據?

是否將原子和互斥體作爲該類的私人成員的一個好動作?

foo.h中

#pragma once 
#include <atomic> 
#include <thread> 
#include <vector> 
#include <mutex> 

class Foo 
{ 
public: 
    Foo(); 
    ~Foo(); 

    void StartThread(); 
    void StopThread(); 
    void SendData(); 

private: 
    std::atomic<bool> dataFlag; 
    std::atomic<bool> runBar; 
    void bar(); 
    std::thread t1; 
    std::vector<int> data; 
    std::mutex mx; 
}; 

foo.c的

#include "FooClass.h" 
#include <thread> 
#include <string> 
#include <iostream> 

Foo::Foo() 
{ 
    dataFlag = false; 
} 

Foo::~Foo() 
{ 
    StopThread(); 
} 

void Foo::StartThread() 
{ 
    runBar = true; 
    t1 = std::thread([=] {bar(); }); 
    return; 
} 

void Foo::StopThread() 
{ 
    runBar = false; 

    if(t1.joinable()) 
     t1.join(); 

    return; 
} 

void Foo::SendData() 
{ 
    mx.lock(); 
    for (int i = 0; i < 5; ++i) { 
     data.push_back(i); 
    } 
    mx.unlock(); 
    dataFlag = true; 
} 

void Foo::bar() 
{ 
    while (runBar) 
    { 
     if(dataFlag) 
     { 
      mx.lock(); 
      for(auto it = data.begin(); it < data.end(); ++it) 
      { 
       std::cout << *it << '\n'; 
      } 
      mx.unlock(); 
      dataFlag = false; 
     } 
    } 
} 

的main.cpp

#include "FooClass.h" 
#include <iostream> 
#include <string> 

int main() 
{ 
    Foo foo1; 

    std::cout << "Type anything to end thread" << std::endl; 

    foo1.StartThread(); 
    foo1.SendData(); 

    // type something to end threads 
    char a; 
     std::cin >> a; 

    foo1.StopThread(); 

    return 0; 
} 
+1

使用std :: lock_guard ,而不是手動調用mx.lock()/解鎖() –

+0

當您啓動線程,你應該是'加入() 'it or'detach()' –

+0

@DmitryKatkevich爲什麼?他稍後加入()'... – vu1p3n0x

回答

0

您確保線程使用RAII技術加入?檢查。

所有的數據訪問/修改都通過atomic s或mutex s保護?檢查。

互斥鎖使用std::lock_guard?不。使用std::lock_guard將您的lock()unlock()調用與RAII進行包裝。這確保即使在鎖內發生異常,鎖也被釋放。

是否將原子和互斥體作爲該類的私人成員的一個好動作?

它既不好也不壞,但在這種情況下,其中Foo是一個std::thread,做工作,並控制同步的包裝,這是有道理的。

使用lambda表達式是一個指向*這發送到線程?

是的,你也可以使用t1 = std::thread([this]{bar();});來使它更加明確。

現在,您的dataFlag鎖定後的分配可能會遇到問題。如果您撥打SendData兩次,以致bar處理第一個,但在設置dataFlag = false之前暫停,以便第二個呼叫添加數據,請將標記設置爲true,以使bar僅將bar設置爲false。然後,您將擁有「已發送」的數據,但bar不認爲有任何要處理的內容。

可能還有其他棘手的情況,但這只是一個例子;將它移入鎖定清除該問題。

例如,您SendData應該是這樣的:

void Foo::SendData() 
{ 
    std::lock_guard<std::mutex> guard(mx); 
    for (int i = 0; i < 5; ++i) { 
     data.push_back(i); 
    } 
    dataFlag = true; 
}