Как работает функция pthread_yield?

#c #multithreading #pthreads #yield

#c #многопоточность #pthreads #выход

Вопрос:

Я реализую библиотеку потоков на C, и я застрял на значении pthread_yield() . Я посмотрел это на странице руководства в терминале, но я не совсем понял объяснение. Кто-нибудь может мне это объяснить?

Комментарии:

1. Не могли бы вы подробнее остановиться на тех частях, которые вам трудно понять?

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

3. На странице руководства говорится, что pthread_yield заставляет вызывающий поток отказываться от процессора. Что это означает?

4. Это важное примечание на справочной странице Linux pthread_yield() : » pthread_yield() предназначено для использования с политиками планирования в реальном времени (т. Е. SCHED_FIFO Или SCHED_RR ). Использование pthread_yield() с недетерминированными политиками планирования, такими как SCHED_OTHER , не определено и, скорее всего, означает, что дизайн вашего приложения нарушен. »

5. Другими словами, если вы хотите, чтобы поток прекратил выполнение, чтобы некоторые другие потоки могли что-то сделать, вы не должны использовать pthread_yield() — или sleep() или что-либо подобное. Вам необходимо использовать надлежащие объекты синхронизации, такие как мьютексы, семафоры и переменные условия.

Ответ №1:

Обратите внимание, что, несмотря на его название, pthread_yield оно не стандартизировано. Например, на странице руководства по Linux говорится об этом:

Этот вызов нестандартный, но присутствует в нескольких других системах. Вместо этого используйте стандартизированный sched_yield(2) .

Спецификации для sched_yield() написаны во многом в тех же терминах pthread_yield() , что и для , однако:

sched_yield() Функция должна заставить запущенный поток отказаться от процессора, пока он снова не станет главой своего списка потоков. Он не принимает аргументов.

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

Ответ №2:

В GLIBC pthread_yield просто вызывает системный вызов sched_yield() (см. nptl/pthread_yield.c в дереве исходных текстов библиотеки):

 /* With the 1-on-1 model we implement this function is equivalent to
   the 'sched_yield' function.  */
int
pthread_yield (void)
{
  return sched_yield ();
}
 

При реализации библиотеки потоков обратите внимание, что приведенный выше исходный код GLIBC (версия 2.31) pthread_yield() приводит к необычному поведению API pthread, которое может быть ошибкой реализации, поскольку оно возвращает непосредственно результат sched_yield() . Как и большинство системных вызовов Linux, последний возвращает -1 и устанавливает errno в случае сбоя (даже если в руководстве указано, что на самом деле он никогда не возвращается с ошибкой). Таким образом, теоретически, это заставляет pthread_yield() возвращать -1 и устанавливать errno в случае ошибки, хотя pthread API обычно возвращает 0 в случае успеха и номер ошибки в случае ошибки (errno не должен быть установлен). Таким образом, руководство неверно или, по крайней мере, не соответствует реализации GLIBC, когда оно описывает возвращаемое значение как:

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении pthread_yield() возвращает 0; при ошибке он возвращает номер ошибки.

Ожидаемый исходный код может быть примерно таким:

 int
pthread_yield (void)
{
  return sched_yield() == -1 ? errno : 0;
}
 

Например, pthread_sigmask() кодируется как:

 int
pthread_sigmask (int how, const sigset_t *newmask, sigset_t *oldmask)
{
[...]
  return sigprocmask (how, newmask, oldmask) == -1 ? errno : 0;
[...]
}
 

что соответствует тому, что указано в руководстве:

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении pthread_sigmask() возвращает 0; при ошибке он возвращает номер ошибки.