Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ understanding multithreading with global variables

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.

Will there be an app-crash if two threads are reading the same variable? Or will there be an app-crash only if one thread writes to 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 ?

Thanks in advance!

like image 888
SaschaP Avatar asked Sep 19 '15 20:09

SaschaP


People also ask

Can threads access global variables C?

But to answer your question, any thread can access any global variable currently in scope. There is no notion of passing variables to a thread. It has a single global variable with a getter and setter function, any thread can call either the getter or setter at any time.

Can multiple threads access a global variables?

can global variables be accessed by two threads? Of course yes, since the several threads of the same process share a common virtual address space.

Is global variable thread safe?

4 Replies. Hello, Your global variable are not thread safe.


3 Answers

Mutiple reads are always thread safe. As soon as one thread is writing to a non-atomic variable var whilst other threads are reading from var you'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:

#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 "";
    }
}
like image 136
Paul Evans Avatar answered Oct 19 '22 09:10

Paul Evans


Will there be an app-crash if two threads are reading the 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 writes to a variable which another thread is currently reading?

Not exactly, but it can lead 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 "";
    }
}

The correct solution is in Paul's answer.

like image 22
Amit Avatar answered Oct 19 '22 10:10

Amit


Will there be an app-crash if two threads are reading the 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 writes to 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?

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

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.

like image 2
Alex Lop. Avatar answered Oct 19 '22 08:10

Alex Lop.