Как использовать pthread_mutex и его функции в классе? - PullRequest
4 голосов
/ 25 мая 2011

Я искал решение в течение многих часов, но не могу найти простой ответ.Я получил класс, который использует pthreads.Фактический указатель на функцию является статическим внутри класса, и мне нужно заблокировать мьютекс, потому что до сих пор я получаю «странные» результаты (параметры не передаются правильно).

Однако pthread_mutex_lock и unlock не будут работатьвнутри функции, данной потоку, потому что она находится в статической функции-члене, но я не могу иметь функцию нестатической, потому что она не будет работать внутри класса, и я не могу переместить ее за пределы класса, потому что она не будетвозможность доступа к необходимой информации.

Следующий код должен объяснить:

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();
  };

И файл cpp:

    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 );

   }

Буду очень признателен, если кто-нибудь сможет пролитьнемного света в этом.Я застрял на несколько часов, и я не мог найти никакой информации вообще.Спасибо!

Ответы [ 4 ]

4 голосов
/ 25 мая 2011

Под «не работает» я предполагаю, что вы имеете в виду, что он не будет компилироваться, так как вы пытаетесь использовать элемент экземпляра в static функции-члене.

Но главный вопрос в том, почему вы пытаетесь использовать темы для этого?

Ваша функция потока в любом случае полностью защищена мьютексом - вы получите ту же (или лучшую) производительность, просто вызвав

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

вместо того, чтобы раскручивать потоки, а затем ждать их завершения.


Но если вы действительно хотите использовать потоки (возможно, вы узнаете о них) и хотите, чтобы ваша статическая функция-член могла иметь дело с членами-экземплярами, вот несколько указателей. Чтобы это работало, вам нужно как-то передать экземпляр объекта Fight в функцию потока static:

// 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;

Наконец, 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;
}
2 голосов
/ 26 мая 2011

Первый вопрос, который я хотел бы задать: вам нужен переносимый код? Если да, никогда не передавайте функцию C ++ в pthread_create. Причина: для интерфейса pthread_create требуется функция, объявленная как extern "C", и вам повезло (благодаря x86 :)), что статический метод-член подходит для этого, но нет гарантии, что такой же будет на другой платформе или компиляторах.

Во-вторых, вы вызвали thread_mutex = PTHREAD_MUTEX_INITIALIZER; после создания мьютекса, насколько я помню, в стандарте говорится, что это разрешено только при инициализации.

И, наконец, pthread_mutex_lock( &thread_mutex ) без статического метода не допускается, поскольку статический метод не имеет доступа к нестатическим членам объекта, поэтому вам нужно передать указатель на ваш объект. Вы можете объявить pthread_mutex_t thread_mutex; и void *thread_run_fighter(void *temp); глобальными, так как я вижу, что в этом случае это будет самый простой способ.

И некоторые примечания: как насчет boost :: threads? Я думаю, что будет лучше использовать его вместо создания собственного решения ...

1 голос
/ 25 мая 2011

Я думаю, что все, что вы пропустили, это использовать &indiv->thread_mutex вместо того, чтобы опускать объект indiv->.

РЕДАКТИРОВАТЬ: Обратите внимание, что, вероятно, лучше использовать статический бросок, а не бросок "дробовик" в стиле C: Individual *indiv = static_cast<Individual*>(temp);

0 голосов
/ 25 мая 2011

внутри статического thread_run_fighter вы используете нестатический thread_mutex.thread_mutex должен быть создан с помощью pthread_mutex_init до его использования.

...