【问题标题】:Threading inside class with atomics and mutex c++使用原子和互斥锁 c++ 在类内部进行线程化
【发布时间】:2016-12-05 05:19:05
【问题描述】:

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

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

使用 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;
}

【问题讨论】:

  • 使用 std::lock_guard 而不是手动调用 mx.lock()/unlock()
  • 当你启动线程时,你应该join()它或者detach()
  • @DmitryKatkevich 为什么?他稍后会join()ing...
  • 我更喜欢保存 detach 以备不时之需
  • 我会将您的作业转移到 dataFlag 到锁内。现在我可以看到它在外面的潜在问题。

标签: c++ multithreading class mutex atomic


【解决方案1】:

您确保线程是使用 RAII 技术连接的?查看。

所有数据访问/修改都通过atomics 或mutexs 保护?查看。

互斥锁使用std::lock_guard?没有。使用std::lock_guard 将您的lock()unlock() 调用与RAII 一起包装。这确保即使在锁内发生异常,锁也会被释放。

将原子和互斥锁作为类的私有成员是一个好的举措吗?

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

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

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

就目前而言,在锁定之后分配dataFlag,您可能会遇到问题。如果您调用SendData 两次以使bar 处理第一个,但在设置dataFlag = false 之前暂停,以便第二个调用添加数据,则将标志设置为true 仅让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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-31
    • 1970-01-01
    • 2021-04-20
    • 2020-12-07
    相关资源
    最近更新 更多