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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32672784/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 14:11:24  来源:igfitidea点击:

C++ understanding multithreading with global variables

c++multithreadingmutex

提问by SaschaP

I have a C++ program which declares some global variables. After that it splits up into several threads to do several tasks. Those threads read and write some of these global variables.

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

Will there be an app-crash if two threads are readingthe same variable? Or will there be an app-crash only if one thread writesto a variable which another thread is currently reading?

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

So if the answer to my second question would be yes, would the following code sample solve this problem?

那么如果我的第二个问题的答案是肯定的,那么下面的代码示例会解决这个问题吗?

#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;
}

furthermore: is this part

此外:这部分是

// ...
if (value == "")
{
    m.unlock();
    return var;
}
// ...

also thread-save?

还线程保存?

And my last question: my program currently uses only one mutex to prevent that two threads (the same function!) are running simultaneously. I am not using mutexes for my global variables. Could it be that this "situation" can cause an app-crash (module: "ntdll.dll") with the exception code 0xc0000005 ?

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

Thanks in advance!

提前致谢!

采纳答案by Paul Evans

Mutiple reads are always thread safe. As soon as one thread is writing to a non-atomic variable varwhilst other threads are reading from varyou're in danger of a race condition. So you're almost there, but use mutex guards (they're RAII and therefore exception safe and cleaner C++), something like:

多读总是线程安全的。一旦一个线程正在写入非原子变量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 "";
    }
}

回答by Amit

Will there be an app-crash if two threads are readingthe same variable?

如果两个线程正在读取同一个变量,是否会发生应用程序崩溃?

No. Never. If you're only reading from multiple threads, you're always safe.

没有永不。如果您只是从多个线程中读取数据,那么您总是安全的。

will there be an app-crash only if one thread writesto a variable which another thread is currently reading?

只有当一个线程写入另一个线程当前正在读取的变量时,才会发生应用程序崩溃吗?

Not exactly, but it canlead to a crash, and that's what is happening in your code. It's not "dangerous" in terms of crashing an application to read/write simultaneously from multiple threads. The worst case is that you get garbaged values at some places. That by it's own won't crash your app, but it can definitely lead to that eventually. The problem is when the data you're reading has a meaning other then a primitive value (like an integer for example). For example, if you're reading a memory address (pointer), and then try to access the memory at that address, but the memory is already freed, then you're in trouble - and that's what happens in your code. The characters of the string have moved to a new address, but you're trying to read the old address.

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

To solve your problem, you should wrap the entire operation inside the lock, and you could use a temporary variable for this:

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

string test(string value = "")
{
    m.lock();
    if (value == "")
    {
        string temp = var;
        m.unlock();
        return temp;
    }
    else
    {
        var = value;
        m.unlock();
        return "";
    }
}
string test(string value = "")
{
    m.lock();
    if (value == "")
    {
        string temp = var;
        m.unlock();
        return temp;
    }
    else
    {
        var = value;
        m.unlock();
        return "";
    }
}

The correct solution is in Paul's answer.

正确的解决方案在保罗的回答中。

回答by Alex Lop.

Will there be an app-crash if two threads are readingthe same variable?

如果两个线程正在读取同一个变量,是否会发生应用程序崩溃?

No you can safely read global variable simultaneously (if you know that no one writes to it at the same time). Read operation doesn't modify the global value so it remains the same and all readers "see" the same value.

不,您可以安全地同时读取全局变量(如果您知道没有人同时写入)。读取操作不会修改全局值,因此它保持不变并且所有读者“看到”相同的值。

Or will there be an app-crash only if one thread writesto a variable which another thread is currently reading?

或者只有当一个线程写入另一个线程当前正在读取的变量时才会发生应用程序崩溃?

Generally no, at least not because of the simultaneous read vs. write operation. The crash may be a side effect of it. For example if you update a pointer value and read it at the same time then you try to access the data to which the pointer points. If the read value is invalid, most likely you will crash.

通常不会,至少不是因为同时读取与写入操作。崩溃可能是它的副作用。例如,如果您更新指针值并同时读取它,那么您将尝试访问指针指向的数据。如果读取值无效,您很可能会崩溃。

furthermore: is this part

// ...
if (value == "")
{
    m.unlock();
    return var;
}
// ...

also thread-save?

此外:这部分是

// ...
if (value == "")
{
    m.unlock();
    return var;
}
// ...

还线程保存?

No. Your mutex mprotects only the local variable valuewhich has no need to be protected since it is local. But then you release the mutex and copy (read) the global varvariable while another thread may write to it. To make it thread safe, either use std::lock_guardand then you won't need manually lock/unlock the mutex. or update the code to this:

不。你的互斥锁m只保护本地变量value,因为它是本地的,所以不需要保护。但是然后您释放互斥锁并复制(读取)全局var变量,而另一个线程可能会写入它。为了使其线程安全,请使用std::lock_guard然后您将不需要手动锁定/解锁互斥锁。或将代码更新为:

m.lock();
if (value == "")
{
    string ret_val(var);
    m.unlock();
    return ret_val;
}

I am not using mutexes for my global variables. Could it be that this "situation" can cause an app-crash

我没有对我的全局变量使用互斥锁。难道这种“情况”会导致应用程序崩溃

As I wrote earlier, yes, as a side effect your app may crash.

正如我之前所写,是的,作为副作用,您的应用程序可能会崩溃。

回答by Lloyd Crawley

Simple question, Simple answer:

简单的问题,简单的回答:

Will there be an app-crash if two threads are reading the same variable?

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

No.

不。

Will there be an app-crash only if one thread writes to a variable which another thread is currently reading?

只有当一个线程写入另一个线程当前正在读取的变量时,才会发生应用程序崩溃吗?

No.

不。

However you really should use locks and mutexes etc to make sure that you get the expected output for programs. Although the program itself will not crash if one thread writes to a variable being read by another thread, what value do you want the reading thread to actually read? The value before it was written to/over or the value after?

但是,您确实应该使用锁和互斥锁等来确保获得程序的预期输出。虽然如果一个线程写入另一个线程正在读取的变量,程序本身不会崩溃,但您希望读取线程实际读取什么值?写入/写入之前的值还是写入之后的值?

回答by mksteve

Not thread safe without mutexes

没有互斥锁就不是线程安全的

Proposed solution is still not quite right.

提出的解决方案仍然不太正确。

var is read outside of the mutex, and could be modified at that time.

var 是在互斥锁之外读取的,并且可以在那时进行修改。

This looks like C++11. If std::stringused shared strings (banned in C++11), that could cause issues with reading.

这看起来像 C++11。如果std::string使用共享字符串(在 C++11 中被禁止),可能会导致读取问题。

In the case of reading+writing, then c0000005 (access violation) could occur if a pointer was modified as it was copied.

在读+写的情况下,如果指针在复制时被修改,则可能发生 c0000005(访问冲突)。