线程类成员函数;线程初始化通过初始化列表

时间:2014-09-03 10:27:02

标签: c++ multithreading

我正在尝试从类成员函数创建一个脚本,并通过类构造函数初始化列表初始化所述线程。

执行线程时,在调用Receive_List.push_back(CurVal++)期间抛出异常,但只需在函数中放置printf()作为第一条指令即可避免此异常。

#include <thread>
#include <list>


class SomeClass
{
    std::thread Receive_Thread;
    std::list<unsigned int> Receive_List;

    void Receive_Main()
    {
        //printf("Hacky Way Of Avoiding The Exception\n");
        const unsigned int MaxVal = 3000;
        unsigned int CurVal = 0;
        while (CurVal < MaxVal)
        {
            Receive_List.push_back(CurVal++);
        }
    }

public:
    SomeClass() :
        Receive_Thread(std::thread(&SomeClass::Receive_Main, this))
    {}

    ~SomeClass()
    {
        Receive_Thread.join();
    }

    void ProcessReceiveList()
    {
        if (!Receive_List.empty())
        {
            printf("Received Val: %i\n", Receive_List.front());
            Receive_List.pop_front();
        }
    }

    bool IsReceiveEmpty()
    {
        return Receive_List.empty();
    }
};


int main()
{
    SomeClass* MyObject = new SomeClass();

    //
    //  Sleep for 1 second to let the thread start populating the list
    std::this_thread::sleep_for(std::chrono::seconds(1));

    while (!MyObject->IsReceiveEmpty())
    {
        MyObject->ProcessReceiveList();
    }

    delete MyObject;
    std::system("PAUSE");
    return 0;
}

为什么会这样?

1 个答案:

答案 0 :(得分:2)

您正在观察的问题是由列表初始化之前启动的线程引起的,这会导致数据竞争,从而导致未定义的行为。添加printf会延迟对列表的第一次访问,因此初始化更有可能在访问之前完成。这确实修复数据竞争;它可以通过在线程之前声明列表来修复:

std::list<unsigned int> Receive_List; 
std::thread Receive_Thread;// WARNING: must be initialised last

您还有一个问题:必须同步对由一个线程修改并由另一个线程更新的数据的所有访问;通常用mutex来保护它。如果没有同步,您将再次出现数据争用,从而导致未定义的行为。

所以在类中添加一个互斥锁以保护列表:

#include <mutex>

class SomeClass {
    std::mutex mutex;
    //...
};

并在您访问列表时将其锁定

while (CurVal < MaxVal)
{
    std::lock_guard<std::mutex> lock(mutex);
    Receive_List.push_back(CurVal++);
}

以及访问列表的其他函数。