sem_wait не работает, как ожидалось? - PullRequest
2 голосов
/ 07 сентября 2010

Ответьте на вопрос моего предыдущего вопроса: Условное ожидание с помощью pthreads

Я изменил свой код, чтобы использовать семафоры вместо мьютексных блокировок и условных сигналов.Тем не менее, я, кажется, натолкнулся на состояние, которое я не могу объяснить.

Вот реферат

function thread work {
   while (true)
   sem_wait(new_work)
   if (condition to exit){
      exit
      }
   while (work based condition){
      if (condition to exit)
         exit
      do work
      if (condition to exit){
      exit
      }
   sem_post(work_done)
   set condition to ready
   }
exit
}

function start_thread(){
sem_wait(work_done)
setup thread work
create work
sem_post(new_work)
return to main()
}

function end_thread(){
set condition to exit
sem_post(new_work)
pthread_join(thread)
clean up
}

объяснение потока управления: основной поток вызывает start_thread, чтобы создать поток, передать некоторую работу.Основной и рабочий продолжают параллельно.Главное может закончить свою работу раньше рабочего или наоборот.Если main заканчивает свою работу раньше, чем работник, работник больше не действителен, и ему нужно сказать, чтобы он прервал свою работу.Это «условие для выхода».Эта функция (start_thread) не создает поток каждый раз, когда его вызывают, только в первый раз.В остальное время он обновляет работу для потока.

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

Поток всегда будет ждать семафора (new_work) перед началом своей работы.Я использую sem new_work, чтобы сообщить потоку, что новая работа теперь доступна и она должна начаться.Поток сообщает управляющей функции (start_thread), что он завершил / прервал работу, используя семафор work_done.

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

«условие для выхода» защищено мьютексом.

Кажется, я не могу понять, что вызывает это условие.

Вот вывод из трассы

 thread 1: sem NEW count, before wait : 0
 thread 1: sem NEW count, before wait : 0
 end post: sem NEW count, before post : 0
 end post: sem NEW count, after post : 1
 thread 1 exit.
 thread exited, cleanup 1

 Entered initialization for thread: 2

 created a thread: 2
 thread: 2 started.

.....


 thread 2: sem NEW count, before wait : 0
 thread 2: sem NEW count, before wait : 0
 thread 2: sem NEW count, before wait : 0
 end post: sem NEW count, before post : 0
 thread 2 exit.
 end post: sem NEW count, after post : 0
 thread exited, cleanup 2

 Entered initialization for thread: 3

 created a thread: 3
 thread: 3 started.

 .....

 thread 3: sem NEW count, before wait : 0
 thread 3: sem NEW count, before wait : 0
 end post: sem NEW count, before post : 0
 end post: sem NEW count, after post : 1
 thread 3: sem NEW count, before wait : 0

На этом этапе поток ожидает на семафоре, а exit_thread ожидает на pthread_join.

Спасибо за вашевремя.

Ответы [ 2 ]

3 голосов
/ 08 сентября 2010

Функции POSIX на sem_t прерываются сигналами и, следовательно, они прерываются любым сигналом, который может получить ваш процесс / поток, в частности, из-за ввода-вывода.

  • всегда исследуйте возвращаемые значения системных вызовов (общие не только для sem_wait)
  • в частности положить sem_wait в цикл while, проверьте на наличие ошибок состояние. Если условие ошибки EINTR перезапустить sem_wait.

То же самое относится и к другим sem_ функциям. Посмотрите на их конкретные условия ошибки и обработайте их специально.

0 голосов
/ 09 сентября 2010

Я нашел ошибку. Я тестировал условие вне мьютекса и менял значение условия внутри блокировки мьютекса. Из-за случайности планирования может случиться так, что основной поток и рабочий поток могут одновременно бороться за блокировку, и оба изменяют значение условия. В зависимости от того, какой поток изменил значение условия в последний раз, рабочий поток продолжит работу, когда он должен выйти. Оба ждут в sem_wait сообщения, которое никогда не придет. работник ожидает новой работы, в то время как основной поток ожидает выхода работника, поскольку он уже установил условие выхода.

Я переместил тест внутрь блокировки мьютекса, и теперь он работает нормально.

Вот фрагмент измененного кода

    }
   sem_post(work_done)
   enter mutex lock
   test condition
       set condition to ready if test is satisfied
   exit lock
   }
...