Как остановить и продолжить pthread? - PullRequest
9 голосов
/ 25 января 2011

Я кодирую в C (на самом деле в OOC, который затем компилируется в C).

Как мне указать потоку ждать в определенной контрольной точке, пока какой-нибудь другой поток не скажет ему продолжить?

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

Ответы [ 4 ]

12 голосов
/ 25 января 2011

Похоже, вы ищете pthread_cond_wait и связанные с ним функции.

Вот цитата из manpage с примером:

Рассмотрим две общие переменные x и y, защищенные mutex mut, и условную переменную cond, которая должна передаваться, когда x становится больше y.

          int x,y;
          pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
          pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

Ожидание, пока x не станетбольше y выполняется следующим образом:

          pthread_mutex_lock(&mut);
          while (x <= y) {
                  pthread_cond_wait(&cond, &mut);
          }
          /* operate on x and y */
          pthread_mutex_unlock(&mut);

Изменения x и y, которые могут привести к тому, что x станет больше y, должны сигнализировать о состоянии, если это необходимо:

          pthread_mutex_lock(&mut);
          /* modify x and y */
          if (x > y) pthread_cond_broadcast(&cond);
          pthread_mutex_unlock(&mut);

В конце концов, он делает то, что вы просите: поток, вызывающий pthread_cond_wait(&cond), блокируется, пока другой поток (например, ваш основной поток) не вызовет pthread_cond_broadcast(&cond).В течение этого времени он находится в состоянии blocked и не потребляет циклов ЦП.

2 голосов
/ 25 января 2011

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

2 голосов
/ 25 января 2011

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

вы можете искать pthread_cond_init, и это должно привести к другим функциям

1 голос
/ 25 января 2011

Для того, чтобы вы знали, что происходит, «узкий цикл» потребляет выделение ЦП вашего потока, как и любой другой код, выполняемый вашим потоком.Разница лишь в том, что это ничего не дает.Ну, я думаю, что согревать ядро ​​- это что-то ... Вы, вероятно, никогда не захотите этого делать, если вы не заботитесь о стоимости переключения контекста, и вы точно не знаете , что время ожидания будет намного корочечем временной интервал вашей нити, который составляет около 1 мс.Я не знаю, является ли сон таким же плохим, как yield (AFAIK yield устанавливает ваш поток в конце списка потоков для активации на вашем уровне приоритета), но оба по крайней мере несут штраф за переключение контекста.Существует стоимость переключения контекста.Переключение контекста - это то, что происходит, когда заканчивается временной поток вашего потока.Он может либо закончиться, потому что вы завершили его с помощью yield или sleep, либо если ядро ​​завершило его, опередив вас.Прочтите о SMP и спин-блокировках, чтобы больше узнать о переключениях контекста и случаях, когда применяется замкнутый цикл.

Кроме того, когда вы спите, вы точно не знаете, когда снова проснетесь.поэтому одна из причин, по которой вы не хотите спать, это то, что вам нужно что-то сделать быстро.Вы можете подождать пару мс, прежде чем их перенести.

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

Здесь не обсуждается, почему вы блокируете мьютекс перед тестированием, если вам нужно дождаться выполнения условия.Причина в том, что у такого кода есть недостаток:

      while (x <= y) {
              pthread_cond_wait(&cond, &mut);
      }

Ваш поток может протестировать (X <= Y), увидеть, что он должен ждать, но быть предварительно извлеченным, прежде чем он присоединится к условиюзначение.Другой поток, который только что изменил x или y, сигнализирует об условии в этом временном интервале, прежде чем первый поток присоединится к условию.Таким образом, сигнал состояния теряется.Таким образом, в конечном итоге, везде, где вы изменяете переменные, влияющие на сигнал, вы должны добавлять блокировки.</p>

      pthread_mutex_lock(&mut);
      /* modify x and y */
      if (x > y) pthread_cond_broadcast(&cond);
      pthread_mutex_unlock(&mut);

Это может означать, что вы добавляете эти блокировки мьютекса во многих разных местах, и ваш код становится более сложным и медленным из-за этого.Возможность зависания потока в ожидании условия всегда есть.У решения loop, test, sleep нет ни одной из этих проблем.Таким образом, если известно, что время ожидания короткое, использование сна в цикле, вероятно, является хорошим решением.Особенно, если вы можете спать на секунду или больше между тестами.Если можете, то не беспокойтесь о мьютексах и условиях.Если время сна короткое, например, 1 мс, а время ожидания длинное, например, минуты или часы, то вы в конечном итоге будете тратить некоторые ресурсы, постоянно просыпаясь и возвращаясь ко сну.Вы должны судить.

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

pthread_mutex_lock(&mut);
/* modify x and y */
if (x > y) {
    pthread_mutex_unlock(&mut);
    pthread_cond_broadcast(&cond);
} else
    pthread_mutex_unlock(&mut);

Спасибо пользователю user576875, чьи примеры кода я скопировал.

...