В следующем коде необходимо вызывать pthread_yield()
в основном потоке, когда он блокируется в ожидании pthread_join()
?
void *myThread(void *result)
{
//do something here
return 0;
}
int main()
{
pthread_t tid;
void *status = 0;
int result;
pthread_create(&tid, NULL, myThread, &result);
// do I need pthread_yield() here?
pthread_join(tid, &status);
return 0;
}
Если нет, то каков допустимый вариант использования pthread_yield()
? В большинстве основных случаев, которые я могу придумать, ОС/планировщик уже автоматически обрабатывает это.
Уступка нити не была необходима в этом столетии.
@Jabberwocky Спасибо, я тоже так подозреваю, просто хочу перепроверить
@user207421, какой век тут ни при чем. Никогда не существовало реализации pthreads, в которой вызов pthread_yield()
был бы полезен в этот момент.
@SolomonSlow Вы говорите конкретно о pthreads. Я говорю о потоке в целом.
@ user207421, вызывающий абонент спрашивает конкретно о программе, которая вызывает pthread_create
, pthread_join
и, возможно, pthread_yield
. Было бы трудно дать осмысленный ответ, не относящийся к библиотеке pthreads. Но ладно, скажем, это вопрос конкретно о pthread_join
, и давайте спросим «нужна ли мне какая-либо уступка потока» перед вызовом pthread_join
? Ответ по-прежнему таков: нет. Никогда не было времени, когда любая уступка была бы выгодна непосредственно перед вызовом pthread_join
.
Я бы сказал, что pthread_join() не является необходимым и является едва ли не худшим из возможных способов использования нескольких потоков.
@MartinJames Можете ли вы рассказать об этом подробнее?
@MartinJames, вызов pthread_join()
из основного потока предотвращает возврат main()
до того, как целевой поток завершит свою работу. Libc вызовет exit
и завершит весь процесс, если main()
будет разрешено просто вернуться. Кроме того, либо вызов соединения, либо pthread_detach
необходимы, если сам процесс будет продолжать работать в течение неопределенного времени после завершения потока. Поток, который не был ни отсоединен, ни присоединен, станет «зомби», который будет продолжать удерживать внутрипроцессные и общесистемные ресурсы после своего завершения. man7.org/linux/man-pages/man3/pthread_join.3.html
... нужно ли вызывать
pthread_yield()
в основном потоке, когда он блокируется в ожиданииpthread_join()
?
Нет, потому что любой вызов, который блокирует ожидание некоторого события, будет отдавать ЦП, пока событие не произойдет. Вот что значит "блоки".
каков допустимый вариант использования
pthread_yield()
?
Отредактировано (Извинения всем, кто уже проголосовал за этот вопрос.)
Больше нет вариантов использования pthread_yield()
. Теперь он устарел в Linux и никогда официально не входил в библиотеку pthreads.† Не следует писать новый код, который вызывает устаревшие функции.
Но некоторые операционные системы поддерживают вызов «выход» (например, sched_yield()
, который появляется как в Linux и в спецификации UNIX.) Вызов «выход» позволяет потоку сказать: «Я хочу, чтобы мой квант времени закончить сейчас». Одним из вариантов использования может быть уступка в узком цикле опроса. Это то, что вы редко увидите в коде, который работает как обычное приложение в ОС общего назначения, потому что ОС предоставляет системные вызовы программы, которые могут ожидать практически любого события; но вы можете увидеть это в коде какого-нибудь встроенного приложения реального времени.
† Спасибо Эндрю Хенле, чей комментарий к первоначальному вопросу предупредил меня об этом факте.
Спин-блокировки пользовательского пространства являются примером, где полезны yields или sleep(0). Хотя вы можете возразить, что спин-блокировки пользовательского пространства — плохая идея, и точка.
@doron, Могли бы поспорить? Я возражал против использования спин-блокировок пользовательского пространства в крупном коммерческом продукте, но доктор компьютерных наук, отвечавший за системную архитектуру, остановил меня. Его точка зрения заключалась в том, что вероятность того, что любые два потока действительно столкнутся на одной из спин-блокировок, была практически нулевой, и что время, сэкономленное за счет спин-блокировки вместо использования мьютекса, стоило риска возможного столкновения. Я сомневался, что неоспоримый мьютекс стоит так дорого, но у меня не было ресурсов, чтобы фактически измерить производительность в реальных условиях.
Linux использует системные вызовы futex (и futex2) для блокировки мьютекса). Если мьютекс не оспаривается (как и должно быть в 99,9% случаев в производительном коде), вызовы ядра вообще не выполняются (обновляются только атомарные переменные)
Не не надо. Как вы думаете, почему это может быть необходимо? Помогает ли это: stackoverflow.com/a/65381133/898348?