用atomics和mutex c ++在类中进行线程化

时间:2016-12-05 05:19:05

标签: c++ multithreading class mutex atomic

我写了这个示例程序来模仿我在一个更大的程序中尝试做的事情。

我有一些数据来自用户并被传递到线程进行某些处理。我在数据周围使用互斥锁,标志在有数据时发出信号。

使用lambda表达式,是一个指向* this发送给线程的指针?我似乎在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 个答案:

答案 0 :(得分:0)

您确保使用RAII技术连接线程吗?校验。

所有数据访问/修改都是通过atomicmutex s保护的?校验。

互斥锁定使用std::lock_guard?不。使用std::lock_guard将您的lock()unlock()来电包裹在RAII中。这确保即使在锁内发生异常,也会释放锁。

  

将原子和互斥体作为班级的私人成员是一个很好的举动吗?

它既不好也不坏,但在这种情况下,Foostd::thread的包装器,它可以工作并控制同步,这是有道理的。

  

使用lambda表达式是指向* this发送到线程的指针吗?

是的,你也可以t1 = std::thread([this]{bar();});使其更明确。

就目前而言,锁定后的dataFlag作业可能会遇到问题。如果您拨打SendData两次,bar处理第一个但在设置dataFlag = false之前暂停,以便第二个调用添加数据,请将标记设置为truebar将其设置回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;
}