samedi 2 décembre 2017

Using infinite loops in std::thread to increment and display a value

Considering the following, simple code:

using ms = std::chrono::milliseconds;
int val = 0;
for(;;)
{
    std::cout << val++ << ' ';
    std::this_thread::sleep_for(ms(200));
}

We see that we infinitely print subsequent numbers each 0.2 second.

Now, I would like to implement the same logic using a helper class and multithreading. My aim is to be able to run something similar to this:

int main()
{
    Foo f;
    std::thread t1(&Foo::inc, f);
    std::thread t2(&Foo::dis, f);
    t1.join();
    t2.join();
}

where Foo::inc() will increment a member variable val of an object f by 1 and Foo::dis() will display the same variable.

Since the original idea consisted of incrementing and printing the value infinitely, I would assume that both of those functions must contain an infinite loop. The problem that could occur is data race - reading and incrementing the very same variable. To prevent that I decided to use std::mutex.

My idea of implementing Foo is as follows:

class Foo {
    int val;
public:
    Foo() : val{0} {}
    void inc()
    {
        for(;;){
            mtx.lock();
            ++val;
            mtx.unlock();
        }
    }
    void dis()
    {
        using ms = std::chrono::milliseconds;
        for(;;){
            mtx.lock();
            std::cout << val << ' ';
            std::this_thread::sleep_for(ms(200));
            mtx.unlock();
        }
    }
};

Obviously it's missing the mtx object, so the line

std::mutex mtx;

is written just under the #includes, declaring mtx as a global variable.

To my understanding, combining this class' definition with the above main() function should issue two, separate, infinite loops that each will firstly lock the mutex, either increment or display val and unlock the mutex so the other one could perform the second action.

What actually happens is instead of displaying the sequence of 0 1 2 3 4... it simply displays 0 0 0 0 0.... My guess is that I am either using std::mutex::lock and std::mutex::unlock incorrectly, or my fundamental understanding of multithreading is lacking some basic knowledge.

The question is - where is my logic wrong?

  • How would I approach this problem using a helper class and two std::threads with member functions of the same object?

  • Is there a guarantee that the incrementation of val and printing of it will each occur one after the other using this kind of logic? i.e. will there never be a situation when val is incremented twice before it being displayed, or vice versa?

Aucun commentaire:

Enregistrer un commentaire