C++理解全局变量的多线程

Sas*_*haP 9 c++ multithreading mutex

我有一个C++程序,它声明了一些全局变量.之后,它分成几个线程来完成几个任务.这些线程读取和写入一些全局变量.

如果两个线程正在读取相同的变量,是否会有应用程序崩溃?或者只有当一个线程写入另一个线程当前正在读取的变量时才会出现应用程序崩溃?

因此,如果我的第二个问题的答案是肯定的,那么以下代码示例是否会解决此问题?

#include <string>
#include <thread>
#include <mutex>
using namespace std;

mutex m;
string var = "foo";

// function to provide read and write access
// "protected" with mutex
string test(string value = "")
{
    m.lock();
    if (value == "")
    {
        m.unlock();
        return var;
    }
    else
    {
        var = value;
        m.unlock();
        return "";
    }
}

void thread1()
{
    // use global variable local
    string localVar = test();
}
void thread2()
{
    // overwrite global variable
    test("bar");
}
void thread3()
{
    // use global variable local
    string localVar = test();
}

int main()
{    
    thread t1(thread1);
    thread t2(thread2);
    thread t3(thread3);

    t1.join();
    t2.join();
    t3.join();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

此外:是这部分

// ...
if (value == "")
{
    m.unlock();
    return var;
}
// ...
Run Code Online (Sandbox Code Playgroud)

线程保存?

我的上一个问题是:我的程序目前只使用一个互斥锁来防止两个线程(同一个函数!)同时运行.我没有在我的全局变量中使用互斥锁.难道这个"情况"会导致应用程序崩溃(模块:"ntdll.dll"),异常代码为0xc0000005吗?

提前致谢!

Pau*_*ans 7

多个读取始终是线程安全的.只要一个线程正在写入非原子变量,var而其他线程正在读取var您处于竞争状态的危险中.所以你几乎就在那里,但是使用互斥锁(它们是RAII,因此异常安全且更干净的C++),类似于:

#include <mutex>
#include <string>
// ...
std::mutex m;
std::string var = "foo";
// ...
std::string test(const std::string& value = "")
{
    std::lock_guard<std::mutex> lock(m);
    if (value == "")
    {
        return var;
    }
    else
    {
        var = value;
        return "";
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @SaschaP - 如果抛出异常,互斥体将被解锁 (4认同)
  • 没有什么你不需要写解锁。 (2认同)

Ami*_*mit 6

如果两个线程正在读取相同的变量,是否会有应用程序崩溃?

没有永不.如果你只是从多个线程中读取,那么你总是安全的.

只有当一个线程写入另一个线程当前正在读取的变量时,是否会出现应用程序崩溃?

不完全是,但它可能导致崩溃,这就是代码中发生的事情.在将应用程序从多个线程同时读/写同时崩溃方面并不"危险".最糟糕的情况是你在某些地方得到了价值.它本身不会崩溃您的应用程序,但它最终肯定会导致.问题是当您正在读取的数据具有除原始值之外的含义(例如整数).例如,如果您正在读取内存地址(指针),然后尝试访问该地址的内存,但内存已经被释放,那么您就遇到了麻烦 - 这就是代码中发生的情况.字符串的字符已移至新地址,但您正在尝试读取旧地址.

要解决您的问题,您应该将整个操作包装在锁内,并且可以使用临时变量:

string test(string value = "")
{
    m.lock();
    if (value == "")
    {
        string temp = var;
        m.unlock();
        return temp;
    }
    else
    {
        var = value;
        m.unlock();
        return "";
    }
}
Run Code Online (Sandbox Code Playgroud)

保罗的回答是正确的解决方案.