Ælex
Ælex

Reputation: 14829

How to use pthread_mutex and it's functions within a class?

I have searched for many hours for a solution, but cannot find an easy answer. I got a class, which uses pthreads. The actual function pointer is static within the class, and I need to lock on a mutex, because so far I get "weird" results (parameters not being passed correctly).

However the pthread_mutex_lock and unlock will not work within the function given to the thread, because it is in a static member function, yet I cannot have the function non static because it won't work inside the class, and I cannot move it outside the class, because it won't be able to access required info.

The following code should explain:

class Fight{

     pthread_mutex_t thread_mutex;
     static void *thread_run_fighter(void *temp);

  public:

    Fight();
    bool thread_round(Individual &a, int a_u, Individual &b, int b_u);
    std::vector<Individual> tournament();
  };

And the cpp file:

    Fight::Fight(){
       thread_mutex = PTHREAD_MUTEX_INITIALIZER;
    }

    bool Fight::thread_round(Individual &a, int a_u, Individual &b, int b_u){

    if (a.saved and b.saved){
       a.uniform = a_u;
       b.uniform = b_u;
       Individual *one = &a;
       Individual *two = &b;      
       pthread_t a_thread, b_thread;
       int a_thread_id, b_thread_id;
       a_thread_id = pthread_create(&a_thread,NULL,Fight::thread_run_fighter,(void*) one);
       b_thread_id = pthread_create(&b_thread,NULL,Fight::thread_run_fighter,(void*) two);

       pthread_join( a_thread, NULL);
       pthread_join( b_thread, NULL); 
       return true;
    }
    else{
       return false;
    }
   }

   void *Fight::thread_run_fighter(void *temp){

     Individual *indiv;
     indiv = (class Individual*)temp;
     pthread_mutex_lock( &thread_mutex );
     indiv->execute(indiv->uniform);
     pthread_mutex_unlock( &thread_mutex );

   }

I would be really grateful if anyone could shed some light into this. I have been stuck for some hours now, and I could not find any info whatsoever. Thank you!

Upvotes: 4

Views: 7323

Answers (4)

tvn
tvn

Reputation: 634

The first question which I'd like to ask: do you need portable code? If yes, never pass C++ function to pthread_create. The reason: interface for pthread_create requires function declared as extern "C", and you are lucky (thanks to x86:) ) that static member method suits for this, but there is no guarantee that the same will be on other platform or compilers.

The second, you have called thread_mutex = PTHREAD_MUTEX_INITIALIZER; after mutex creation, as far as I remember standard say that this is allowed on initialization only.

And finally, pthread_mutex_lock( &thread_mutex ) withing static method will not allowed because static method does not have access to object's non-static members, so you need to pass a pointer to you object. You may declare pthread_mutex_t thread_mutex; and void *thread_run_fighter(void *temp); as global, as I see it will be the simplest way in this case.

And some notes: what about boost::threads? I think it will be better to use it instead of creating your own solution...

Upvotes: 2

Michael Burr
Michael Burr

Reputation: 340168

By 'doesn't work' I assume you mean it won't compile since you're trying to use an instance member in a static member function.

But the bigger question is why are you trying to use threads for this?

The thread function you have is entirely protected by the mutex anyway - you'll get the same (or better) performance by simply calling

a.execute(a.uniform);
b.execute(b.uniform);

instead of spinning up the threads then waiting for them to complete.


But if you really want to use threads (maybe you're learning about them) and you want your static member function to be able to deal with instance members, here are some pointers. To get that to work, you'll need to somehow pass an instance of the Fight object to the static thread function:

// somewhere in `class Fight` definition:
//
// a structure that will let you pass a Fight* instance pointer
//  along with an Individual* to work on in the the
//  thread function

struct context {
    Fight* me;
    Individual* indiv;
};



// ...

// in Fight::thread_round():
//  package up data to pass to the thread function
context one = {this, &a };  // instead of Individual *one = &a;
context two = {this, &b };  // instead of Individual *two = &b;

Finally, Fight::thread_run_fighter():

void *Fight::thread_run_fighter(void *temp)
{
    // pull out the Fight object instance and the Individual
    //  object to work on
    context* ctx = (context*) temp;
    Individual *indiv = ctx->indiv;
    Fight* me = ctx->me;

    // do the work (in a pretty serialized fashion, unfortunately)
    pthread_mutex_lock( &me->thread_mutex );
    indiv->execute(indiv->uniform);
    pthread_mutex_unlock( &me->thread_mutex );

    return 0;
}

Upvotes: 4

Mario The Spoon
Mario The Spoon

Reputation: 4859

inside of the static thread_run_fighter you are using the non static thread_mutex. thread_mutex must be created with pthread_mutex_init prior to it's use.

Upvotes: 0

Mark B
Mark B

Reputation: 96233

I think all you missed was to use &indiv->thread_mutex instead of omitting the indiv-> object.

EDIT: Do note that it's probably better to use a static cast rather than the C-style "shotgun" cast: Individual *indiv = static_cast<Individual*>(temp);

Upvotes: 1

Related Questions