Постоянная блокировка мьютекса вызывает тупик? - PullRequest
1 голос
/ 15 июня 2010

У меня проблема с мьютексами (pthread_mutex в Linux), когда если поток снова блокирует мьютекс сразу после его разблокировки, другой поток не очень успешно получает блокировку. Я приложил тестовый код, в котором создается один мьютекс, а также два потока, которые в бесконечном цикле блокируют мьютекс, некоторое время спят и снова его разблокируют.

Вывод, который я ожидаю увидеть, это «живые» сообщения от обоих потоков, по одному от каждого (например, 121212121212. Однако я получаю, что один поток получает большинство блокировок (например, 111111222222222111111111 или просто 1111111111111 ...).

Если я добавляю usleep (1) после разблокировки, все работает как положено. Очевидно, когда поток переходит в режим SLEEP, другой поток получает свою блокировку - однако я ожидал этого не так, поскольку другой поток уже вызвал pthread_mutex_lock. Я подозреваю, что это способ, которым это реализовано, в том, что поток actice имеет приоритет, однако это вызывает определенную проблему в этом конкретном тестовом примере. Есть ли способ предотвратить это (кроме добавления намеренно большой задержки или какой-либо сигнализации) или где моя ошибка в понимании?

#include <pthread.h>
#include <stdio.h>

#include <string.h>
#include <sys/time.h>
#include <unistd.h>

pthread_mutex_t mutex;

void* threadFunction(void *id) {
 int count=0;

 while(true) {
  pthread_mutex_lock(&mutex);
  usleep(50*1000);
  pthread_mutex_unlock(&mutex);
  // usleep(1);

  ++count;
  if (count % 10 == 0) {
   printf("Thread %d alive\n", *(int*)id);
   count = 0;
  }
 }

 return 0;
}

int main() {
 // create one mutex
 pthread_mutexattr_t attr;
 pthread_mutexattr_init(&attr);
 pthread_mutex_init(&mutex, &attr);

 // create two threads
 pthread_t thread1;
 pthread_t thread2;

 pthread_attr_t attributes;
 pthread_attr_init(&attributes);

 int id1 = 1, id2 = 2;
 pthread_create(&thread1, &attributes, &threadFunction, &id1);
 pthread_create(&thread2, &attributes, &threadFunction, &id2);

 pthread_attr_destroy(&attributes);

 sleep(1000);
 return 0;
}

Ответы [ 3 ]

2 голосов
/ 15 июня 2010

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

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

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

Если вы хотите чередовать потоки, вам нужно что-тоболее детерминированный, чем мьютексы, такие как набор условных переменных:

1 голос
/ 15 июня 2010

Это не тупик, это даже не livelock. Это просто случай отсутствия 1001 * справедливости . Если это важно для вас, вы должны использовать примитивы, которые обеспечивают отсутствие голодания, например, мьютекс в очереди.

0 голосов
/ 15 июня 2010

Когда первый поток разблокирует мьютекс, конечно, будет некоторая задержка, прежде чем это изменение станет доступным для другого потока.Это, вероятно, дольше, чем требуется первому потоку для повторной блокировки мьютекса, поскольку на этот раз ждать не нужно.

...