2016-12-05 47 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; 
}