Как читать/записывать общую переменную с помощью pthreads?

StackOverflow https://stackoverflow.com/questions/607374

  •  03-07-2019
  •  | 
  •  

Вопрос

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

Тема 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 );
}
Это было полезно?

Решение

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

Тема 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);

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

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

Другие советы

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top