C++可以在结构中声明原子变量来保护这些成员吗?

P.S*_*.S. 3 c++ windows multithreading atomic

在共享文件中声明和定义结构.

Windows API创建的两个线程CreateThread()都可以看到它的实例:

struct info
{
    std::atomic<bool> inUse; 
    string name;

};
info userStruct; //this guy shared between two threads
Run Code Online (Sandbox Code Playgroud)

线程1连续锁定/解锁以写入结构中的成员(测试的值相同):

    while (1)
    {
        userStruct.inUse = true;
        userStruct.name= "TEST";
        userStruct.inUse = false;
    }   
Run Code Online (Sandbox Code Playgroud)

线程2 只是读取和打印,只有它碰巧解锁它

    while (1)
    {
        while (! userStruct.inUse.load() )
        {
            printf("** %d, %s\n\n", userStruct.inUse.load(), userStruct.name.c_str());
            Sleep(500); //slower reading
        }

        printf("In Use!\n");
    }
Run Code Online (Sandbox Code Playgroud)

期待看到很多:

"正在使用!"

如果它进入,每次一次,解锁时:

"0,TEST"

..它确实如此.

但也看到:

" 1,测试"

如果原子布尔为1,我不希望看到它.

我究竟做错了什么?

Chr*_*phe 5

您的代码不是线程安全的.原子是原子的.但if声明不是!

怎么了:

Thread 1                                Thread 2               Comment 

while (! userStruct.inUse.load() )                             ---> InUse is false 
==> continues loop 
                                        inUse = true           
==> continues loop already started
printf(...) 
Run Code Online (Sandbox Code Playgroud)

在最坏的情况下,由于数据竞争可能会有UB(一个线程2修改字符串,线程1在修改期间读取字符串).

解:

由于您打算将原子用作锁,只需使用为此类同步设计的实际锁,使用std::mutexa std::lock_guard.

例如:

struct info
{
    std::mutex access; 
    string name;
}; 
Run Code Online (Sandbox Code Playgroud)

第一个线程将是:

while (1)
{
    std::lock_guard<std::mutex> lock(userStruct.access); // protected until next iteration
    userStruct.name= "TEST";
}   
Run Code Online (Sandbox Code Playgroud)

然后,第二个线程可以尝试以非阻塞方式访问互斥锁:

while (1)
{
    {  //  trying to lock the mutex
        std::unique_lock<std::mutex> lock(userStruct.access, std::try_to_lock);
        if(!lock.owns_lock()){   // if not successful do something else
            std::cout << "No lock" <<std::endl; 
        }
        else                     // if lock was successfull
        {
            std::cout << "Got access:" << userStruct.name <<std::endl;
        }
    } // at this stage, the lock is released.
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
Run Code Online (Sandbox Code Playgroud)

在线演示


Tyk*_*ker 5

你正在对原子变量执行2次distict加载以检查然后输出.值可以在负载之间变化.你的字符串变量也有数据竞争.

您可以使用std :: atomic_flag或互斥锁轻松修复它

struct info
{
    std::atomic_flag inUse;
    std::string name;

};

//writer
while (1)
{
    if (!userStruct.inUse.test_and_set()) {
        userStruct.name= "TEST";
        userStruct.inUse.clear();
    }
}

//reader
while (1)
{
    if (!userStruct.inUse.test_and_set())
    {
        printf("** %s\n\n", userStruct.name.c_str());
        userStruct.inUse.clear();
    }
    printf("In Use!\n");
}
Run Code Online (Sandbox Code Playgroud)

你无法检查atomic_flag中的值,因为检查锁的值几乎总是一个坏主意,因为值可以在你采取行动之前改变.