Pthreads создаются с двойными идентификаторами - PullRequest
0 голосов
/ 10 апреля 2019

Я использую темы, чтобы смоделировать количество клиентов, которые хотят забронировать места в клубе. Предполагается, что каждый клиент (поток) имеет уникальный идентификатор, и каждый поток получает некоторые данные через структуру (идентификатор включен в эти данные внутри структуры). Проблема в том, что некоторые потоки имеют один и тот же идентификатор, когда я выполняю код, и мне интересно, как это происходит, поскольку для создания потока необходимо выполнить еще одну итерацию цикла for, и таким образом, thread_id обновляется другим значением, прежде чем структура будет передана новому потоку и создан следующий поток.

Может кто-нибудь помочь мне понять, почему появляются повторяющиеся значения и как это исправить? Спасибо!

int main(int argc, char *argv[])
{
    ThreadData threadData; //the struct which is used as input in the 
    // thread_transaction method, contains the id and other thread 
    //information
    pthread_t* thread_ids = (pthread_t*)malloc(sizeof(pthread_t) * 
    n_cust);

    for(i = 0; i < n_cust; i++){
        threadData.thread_id = i;
        pthread_create(&thread_ids[i], NULL, &thread_transaction, (void *) 
        (&threadData));
    }

    for(j=0; j < n_cust; j++) {
        pthread_join(thread_ids[j], NULL);
    }
    printf("SEAT ARRANGEMENT: \n");
    for(y=0; y<Nseat;y++){
        printf("Seat %d / Costumer %d, ", y, threadData.seats_array[y]);
    }

    free(thread_ids);

    return 0;
  }


 void* thread_transaction(void* arg)
 {
   ThreadData* threadData = (ThreadData*) arg;
   pthread_mutex_lock(&id_mut); //i even tried mutex-locking the ID
   int id= threadData->thread_id;
   pthread_mutex_unlock(&id_mut);
  .
  .
  .
   printf("Your reservation is completed successfully. Your transaction 
   number is %d ", id); //for 5 customers eg. it printed 4 0 4 2 2
 }

1 Ответ

1 голос
/ 10 апреля 2019

Мне интересно, как это происходит с тех пор, чтобы необходимо создать еще одну итерацию цикла for, и это Кстати, идентификатор потока обновляется другим значением, прежде чем структура передается новому потоку и создается следующий поток.

Вы почти ответили на свой вопрос. Да, на следующей итерации цикла вы обновляете thread_id той же структуры, которую вы представили предыдущему потоку. Итак, что, по вашему мнению, произойдет, если предыдущий поток еще не прочитал свое значение идентификатора? Ответ: он может прочитать значение, предназначенное для следующего потока, вместо своего собственного.

В целом, у вас есть гонка данных, потому что элемент thread_id совместно используется основным потоком и потоком, который он только что создал, они обращаются к нему без надлежащей синхронизации, * и один из обращений это запись. Программа, которая содержит гонку данных, имеет неопределенное поведение, поэтому потоки, получающие неправильные идентификаторы, - это наименьшее количество ваших забот.

Возможно, вы могли бы использовать семафор для обеспечения необходимой синхронизации и упорядочения между основным потоком и каждым новым, чтобы основной поток не изменял threadData преждевременно или небезопасно. Но я думаю, что было бы проще и более общим дать каждому потоку отдельный, отдельный ThreadData объект, независимо от того, был ли он динамически размещен или из обычного массива из них.


* Хотя новый поток защищает свой доступ мьютексом, этого недостаточно. Все доступы должны быть защищены одним и тем же мьютексом, чтобы обеспечить надлежащую синхронизацию. Более того, даже это не обеспечит необходимый относительный порядок записи и чтения.

...