boost::thread not updating global variable

619 Views Asked by At

I am using a wrapper function in an external software to start a new thread, which updates a global variable, but yet this seems invisible to the main thread. I cant call join(), not to block the main thread and crash the software. boost::async, boost::thread and boost::packaged_task all behave the same way.

uint32 *Dval;

bool hosttask1()
{

        while(*Dval<10)
        {
            ++*Dval;
            PlugIn::gResultOut << " within thread global value: " << *Dval << std::endl;    
            Sleep(500);
        }


return false;
}



void SU_HostThread1(uint32 *value)
{

Dval = value; 
*Dval = 2;
PlugIn::gResultOut << " before thread: " << *value <<  " before thread global: " << *Dval << std::endl;

    auto myFuture = boost::async(boost::launch::async,&hosttask1);

    //boost::thread thread21 = boost::thread(&hosttask1);
    //boost::packaged_task<bool> pt(&hosttask1);
    //boost::thread thread21 = boost::thread(boost::move(pt)); 
}

When I call the function:

number a=0 
su_hostthread1(a)
sleep(2) //seconds
result(" function returned "+a+"  \n")

OUTPUT:

before thread value: 2 before thread global value: 2
 within thread global value: 3
 within thread global value: 4
 within thread global value: 5
 within thread global value: 6
 function returned 2  
 within thread global value: 7
 within thread global value: 8
 within thread global value: 9
 within thread global value: 10

Any ideas? Thanks in advance!

3

There are 3 best solutions below

2
Gem Taylor On

Likely this is because the compiler doesn't generally think about multithreading when optimising your code. If has seen you code checks a value repeatedly, and it knows that in single threading that value cannot change, so it just omitted the check.

If you declare the variable as volatile, then it will probably generate less efficient code that checks more often.

Of course you have to also understand that when a value is written, there are circumstances when it may not all be written in one go, so if you are unlucky enough to read it back when it is half-written, then you get back a garbage value. The fix for that is to declare it as std::atomic (which is automatically considered volatile by the optimiser), and then even more complex code will be emitted to ensure that the write and the read cannot intersect (or different processor primitives might be used for small objects such as integers)

most variables are not shared between threads, and when they are it is up to the programmer to identify those and balance optimisation against the thread synchronisation needs during design.

1
Ulrich Eckhardt On

If you share data between threads, you must syncronize access to that data. The two possible ways are a mutex protecting said data and atomic operations. The simple reason is that caches and read/write reordering (both by CPU and compiler) exist. This is a complex topic though and it's nothing that can be explained in an answer here, but there are a few good books out there and also a bunch of code that gets it right.

1
Don I On

The following code correctly reproduces what I intend to do. Mainly, the thread updates a global variable which the main thread correctly observes.

#include "stdafx.h"
#include <iostream>

#include <boost/thread.hpp>
#include <boost/chrono.hpp>

unsigned long *dataR;

bool hosttask1()
{
    bool done = false;
    std::cout << "In thread global value: " << *dataR << "\n"; //*value11 <<  *dataL << 
    unsigned long cc = 0;
    boost::mutex m;

        while (!done)
        {
            m.lock();
            *dataR = cc;
            m.unlock();
            cc++;
            std::cout <<  "In thread loop global value: "<< *dataR << "\n";
            if (cc==5) done = true;
        }


return done;
}

void SU_HostThread1(unsigned long *value)
{
    dataR = value;
    std::cout << "Before thread value: " << *value << " Before thread global value: " << *dataR << "\n"; //*value11 <<  *dataL << 
    auto myFuture = boost::async(boost::launch::async, &hosttask1);
    return;
}

int main()
{
    unsigned long value =1;
    unsigned long *value11;
    value11 = &value;

    SU_HostThread1(value11);

    boost::this_thread::sleep(boost::posix_time::seconds(1));
    std::cout << "done with end value: " << *value11 << "\n";

    return 0;
}

output:

Before thread value: 1 Before thread global value: 1
In thread global value: 1
In thread loop global value: 0
In thread loop global value: 1
In thread loop global value: 2
In thread loop global value: 3
In thread loop global value: 4
done with end value: 4

Yet when I copy this exactly to the SDK of the external software, the main thread does not update global value. Any ideas how this is so? Thanks

output in external software:

before thread value: 1 before thread global value: 1
In thread global value: 1
In thread loop global value: 0
In thread loop global value: 1
In thread loop global value: 2
In thread loop global value: 3
In thread loop global value: 4
done with end value: 1