Boost logo

Boost Users :

Subject: Re: [Boost-users] [Boost.Thread]
From: Gottlob Frege (gottlobfrege_at_[hidden])
Date: 2010-01-28 13:02:23


inlined below:

On Thu, Jan 28, 2010 at 12:23 PM, Andrew Chinkoff <achinkoff_at_[hidden]> wrote:
> Hi.
>
> There is a test program I would to be explained to me:
>
> *** BEGIN OF TEST PROGRAM ***
> #include <stdio.h>
> #include <boost/thread.hpp>
>

//> #define USE_SPINLOCKS

#define USE_ATOMICS
(you are using atomics, not spinlocks)

> //#define USE_MUTEXES
>
> boost::thread th1;
> boost::thread th2;
>
> boost::mutex mutex;
>
> int global_int = 0;
>

// put the mutex and/or atomics inside this function,
// where it is really needed - protecting you global data - instead of
in your for loop
int read_global_int()
{
> #ifdef USE_MUTEXES
>         boost::mutex::scoped_lock locker(mutex);
      return global_int;

#elif USE_ATOMICS

      // add 0 to global_int. Seems odd, but by doing this with
atomic __sync functions
      // we guarantee proper memory ordering and visibility, as well
as atomicity
      return __sync_fetch_and_add(&global_int, 0);

> #else
>                 ERROR__WRONG_COMPILED;
> #endif

}

//> bool IsNotEven(int code)
// better name:
bool IsOdd(int code)
> {
// no longer grab mutex here. This is now a useful function for *any* integer
         return !!(code & 1); // using !! to convert to bool
> }
>
> void thread_func()
> {
>         for(int i = 0; i < 1000000; ++i)
>         {
             // mutex/atomic handling is inside read_global_int()
                 if(IsOdd(read_global_int()))
>                         global_int+=9; // what about mutex/atomic here?
>                 else
>                         global_int+=1; // and here?
>         }
> }
>
> int main()
> {
>         th1 = boost::thread(&thread_func);
>         th2 = boost::thread(&thread_func);
>         th1.join();
>         th2.join();
>         printf("global_int = %d\n", global_int);
>
>         return 0;
> }
> *** END OF TEST PROGRAM ***
>
> Results of test program:
>
> 1) Test program compiled with USE_SPINLOCKS.
> Outputs are always:
> "global_int = 10"
> "global_int = 10"
> "global_int = 10"
>
> 2) Test program compiled with USE_MUTEXES.
> Outputs differ from each other:
> "global_int = 10000008"
> "global_int = 10000000"
> "global_int = 9763210"
>
> Could you explain me why outputs produced with USE_SPINLOCKS compilation
> differ from USE_MUTEXES ones?
> And what is the difference between (1) and (2) lines?
>

So now they should both look like (2).

In order to get a consistent result (global_int = 10000000), you need
to replace your global_int += 9 and += 1 with __sync instructions.
ie

increase_global_int(int inc)
{
     // TO DO
     // do this atomically or with locks:
     // global_int += inc;
}

> Best,
> Andrew.
>

Tony


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net