Как мне прочитать / записать общую переменную с помощью pthreads? - PullRequest
3 голосов
/ 03 марта 2009

У меня есть два потока, использующих C pthreads на Linux. Один из них записывает данные, а другой читает их. Я использую переменную, чтобы разрешить поток чтения, когда разрешено чтение, и запись, когда разрешено. Таким образом, мьютекс применяется к этой логической переменной с именем "newData". У меня вопрос: нужно ли блокировать / разблокировать мьютекс вокруг доступа внутри условия «если»? Оба способа работают, но я думаю, только потому, что шансы перекрытия записи / чтения над этой переменной очень малы. Я показываю обе альтернативы, чтобы лучше объяснить мой вопрос:

Тема 1:

pthread_mutex_lock( &lattice_mutex );
if (!newData) {
    pthread_mutex_unlock( &lattice_mutex );
    uchar *lattice_pos = lattice;
    int i;
    for(i=0; i<size; i++) {
        *lattice_pos = rand()%CHAR_MAX;
        lattice_pos++;
    }
    pthread_mutex_lock( &lattice_mutex );
    newData = TRUE;
    pthread_mutex_unlock( &lattice_mutex );
} else {
    pthread_mutex_unlock( &lattice_mutex );
}

Тема 2:

pthread_mutex_lock( &lattice_mutex );
if(newData) {
    pthread_mutex_unlock( &lattice_mutex );
    renderUpdate();
    pthread_mutex_lock( &lattice_mutex );
    newData = FALSE;
    pthread_mutex_unlock( &lattice_mutex );
} else {
    pthread_mutex_unlock( &lattice_mutex );
}

Вторая версия, которая работает, но я не знаю, верна ли она:

Тема 1:

if (!newData) {
    uchar *lattice_pos = lattice;
    int i;
    for(i=0; i<size; i++) {
        *lattice_pos = rand()%CHAR_MAX;
        lattice_pos++;
    }
    pthread_mutex_lock( &lattice_mutex );
    newData = TRUE;
    pthread_mutex_unlock( &lattice_mutex );
}

Тема 2:

if(newData) {
    renderUpdate();
    pthread_mutex_lock( &lattice_mutex );
    newData = FALSE;
    pthread_mutex_unlock( &lattice_mutex );
}

Ответы [ 2 ]

4 голосов
/ 03 марта 2009

Это происходит от вашей первой версии - это несколько проще.

Тема 1: писатель

pthread_mutex_lock(&lattice_mutex);
if (!newData) {
    pthread_mutex_unlock(&lattice_mutex);  // Omit?
    uchar *lattice_pos = lattice;
    int i;
    for (i = 0; i < size; i++)
        *lattice_pos++ = rand() % CHAR_MAX;
    pthread_mutex_lock(&lattice_mutex);   // Omit?
    newData = TRUE;
}
pthread_mutex_unlock(&lattice_mutex);

Тема 2: читатель

pthread_mutex_lock(&lattice_mutex);
if (newData) {
    pthread_mutex_unlock(&lattice_mutex);   // Omit?
    renderUpdate();
    pthread_mutex_lock(&lattice_mutex);     // Omit?
    newData = FALSE;
}
pthread_mutex_unlock(&lattice_mutex);

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

Добавлено: я думаю, что вторая версия ошибочна - она ​​не защищает должным образом решетку.

3 голосов
/ 03 марта 2009

Первая версия верна, вам нужен мьютекс как для записи, так и для чтения.

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

Обратите внимание, что код, вероятно, не самый лучший, который вы можете сделать, потому что он никогда не спит (использует занятое ожидание). Если вы хотите дождаться данных в любом потоке, вам придется использовать условную переменную с мьютексом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...