Условные переменные в linux

Русские Блоги

Учебная поездка по Linux (33) —- переменные условия

Условные переменные являются важной концепцией в синхронизации потоков, о которой мы много раз упоминали в предыдущих статьях.

Переменная условия

Условная переменная (cond) является широко используемым методом для реализации логики «ожидания —> пробуждения» в многопоточных программах и представляет собой механизм межпроцессной синхронизации. Переменные условия используются для блокировки потока, пока условие не будет выполнено, Обычно условные переменные и мьютекс используются вместе , Как правило, условная переменная имеет два состояния: (1) один или несколько потоков зависают при ожидании «условия установки условной переменной» и (2) другой поток уведомляет другие потоки, когда условие условной переменной удовлетворяется.

Почему условные переменные всегда используются вместе с блокировками мьютекса?

На самом деле есть две причины:

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

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

Есть два потока, которые вносят глобальную переменную count. Начальное значение count равно 0. Задачи этих двух потоков: Поток 1 отвечает за добавление значения счетчика к 10, а Поток отвечает за очистку счетчика после того, как выходные данные потока 1 добавляют счет к 10, который чередуется.

#include #include #include int count=0; pthread_mutex_t myMutex=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t myCond=PTHREAD_COND_INITIALIZER; void* threadHandle1(void* argv) < while(1) < pthread_mutex_lock(&myMutex); ++count; pthread_mutex_unlock(&myMutex); // Оставим достаточно времени для других потоков, чтобы бороться за блокировки sleep(1); >> void* threadHandle2(void* argv) < while(1) < // Чтобы гарантировать, что когда поток входит в критическую секцию, значение count не будет изменено. if(count==10) < pthread_mutex_lock(&myMutex); if(count==10) < printf("%d\n",count); count=0; >pthread_mutex_unlock(&myMutex); > printf("%d\n",count); sleep(1); > > int main()

Хотя это всего лишь простая двухпоточная операция сложения, поток 1 и поток 2 должны постоянно обмениваться контролем над блокировкой, что, несомненно, окажет некоторое ненужное давление на систему, поскольку мьютекс имеет только два Переменные состояния (заблокированные и разблокированные) и условия могут улучшить отсутствие мьютекс-блокировок на этой стороне.

#include #include #include int count=0; pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond=PTHREAD_COND_INITIALIZER; void* threadHandle1(void* argv) < while(1) < pthread_mutex_lock(&mutex); ++count; printf("thread1(mutex):count=%d\n",count); pthread_mutex_unlock(&mutex); pthread_mutex_lock(&mutex); if(count==5) < if(pthread_cond_signal(&cond)==0) < printf("thread1:(count=5)signal\n"); >> if(count>=10) < if(pthread_cond_signal(&cond)==0) < printf("thread1:(count=10)signal\n"); >> pthread_mutex_unlock(&mutex); printf("thread1:(cond)unlock\n"); sleep(1); > > void* threadHandle2(void* argv) < while(1) < pthread_mutex_lock(&mutex); while(count<10) < // зачем использовать while? // Неправильно установлено время предотвращения пробуждения сигнала. printf("thread2(while):count=%d\n",count); // Открываем блокировку до возврата функции и закрываем блокировку после возврата функции. pthread_cond_wait(&cond,&mutex); printf("condWait\n"); >if(count>=10) < printf("thread2(if):count=%d\n",count); count=0; >pthread_mutex_unlock(&mutex); printf("mutexUnlock\n"); > > int main()

Эта функция имеет три функции:

Читайте также:  Альт линукс общая папка

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

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

(1) Зачем блокировать часть условной переменной в потоке 2?

(2) Почему бы не использовать if вместо if при оценке условных переменных?

Зачем блокировать часть условной переменной в потоке 2?

Если блокировки нет, предположим, что когда поток оценивает, когда поток 1 добавляет значение count к 9, поток 2 оценивает значение count. В это время значение count равно 9, и поток 2 будет Войдите в цикл while, дождитесь выполнения условия потока 1 и разбудите себя. Но в этот момент, когда поток 1 еще не выполнил pthread_cond_wait, поток 1 изменяет значение счетчика на 10 и отправляет сигнал, чтобы попытаться разбудить поток 2. Поток 2 не выполнил ожидание, поэтому он не получит этот сигнал, затем выполнит ожидание и продолжит ожидание сигнала потока 1, но поток 1 выполнит задачу, и он уже отправил сигнал пробуждения, поэтому возникла проблема.

Следовательно, необходимо блокировать переменную при оценке условной переменной, чтобы другие потоки не могли изменить переменную, что может гарантировать правильность значения условной переменной при оценке. что Роль мьютекса заключается не в том, чтобы защитить переменные условия, а в том, чтобы защитить значение общих переменных от изменения во время оценки состояния. 。

Почему бы вам не использовать if при оценке условных переменных?

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

Как и в предыдущей программе: наша идея состоит в том, чтобы разбудить поток 2, когда поток 1 добавляет результат счета к 10, но поток 1 пробуждает поток 2, когда число равно 5. Если вы используете здесь Что-то пошло не так Таким образом, программа не может гарантировать, что синхронизация сигнального потока, пробуждающего поток ожидания, правильная, поэтому, если требуется несколько суждений, вам нужно использовать вместо вместо if.

Когда сигнал просыпается поток

Анализ результатов приведенного выше кода показывает, что функция pthread_cond_signal предназначена только для пробуждения потока, заблокированного условной переменной, но эта функция не изменяет состояние блокировки. И pthread_cond_wait изменит состояние мьютекса.

Здесь есть такая проблема: (1) сначала разблокировать, затем проснуться, (2) сначала проснуться, затем разблокировать. Поскольку ожидание снова пробуждено, произойдет операция блокировки.

(1) Сначала разблокируйте мьютекс, а затем разбудите спящий поток.

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

Читайте также:  Настройка терминала kali linux

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

(2) Разбудите спящую нить, прежде чем разблокировать мьютекс.

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

недостаток: Увеличит количество пользовательских режимов для переключения режима ядра, увеличив потребление ресурсов.

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

Источник

Условные переменные

Условные переменные (conditional variable, completion variable) — простое средство синхронизации между двумя заданиями, которые работают в режиме ядра, когда необходимо, чтобы одно задание послало сигнал другому о том, что произошло некоторое событие. При этом одно задание ожидает на условной переменной, пока другое задание не выполнит некоторую работу. Когда другое задание завершит выполнение своей работы, оно использует условную переменную для того, чтобы возвратить к выполнению все ожидающие на ней задания. Если это кажется похожим на работу семафора, то именно так оно и есть, идея та же. В действительности, условные переменные просто обеспечивают простое решение проблемы, для которой в других ситуациях используются семафоры. Например, в системном вызове vfork() условная переменная используется для возврата к выполнению родительского процесса при завершении порожденного.

Условные переменные представляются с помощью структуры struct completion, которая определена в файле .

Статически условная переменная может быть создана с помощью макроса

Динамически созданная условная переменная может быть инициализирована с помощью функции init_completion().

Задание, которое должно ожидать на условной переменной, вызывает функцию wait_for_completion(). После того как наступило ожидаемое событие, вызов функции complete() посылает сигнал заданию, которое ожидает на условной переменной, и это задание возвращается к выполнению. В табл. 9.7 приведены методы работы с условными переменными.

Таблица. 9.7. Методы работы с условными переменными

Метод Описание init_completion(struct completion*) Инициализация динамически созданной условной переменной в заданной области памяти wait_for_completion(struct completion*) Ожидание сигнала на указанной условной переменной complete(struct completion*) Отправка сигнала всем ожидающим заданиям и возвращение их к выполнению

Для примеров использования условных переменных смотрите файлы kernel/sched.c и kernel/fork.с. Наиболее часто используются условные переменные, которые создаются динамически, как часть структур данных. Код ядра, который ожидает на инициализацию структуры данных, вызывает функцию wait_for_completion(). Когда инициализация закончена, ожидающие задания возвращаются к выполнению с помощью вызова функции complete().

Читайте также

Условные переменные

Условные переменные Условные переменные (conditional variable, completion variable) — простое средство синхронизации между двумя заданиями, которые работают в режиме ядра, когда необходимо, чтобы одно задание послало сигнал другому о том, что произошло некоторое событие. При этом одно

Читайте также:  Линукс подключить общую папку

Условные выражения

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

Функции и переменные. Локальные переменные

Функции и переменные. Локальные переменные Объявленные ранее функции создают внутри своего тела собственные переменные. Это так называемые локальные переменные. Такие переменные доступны только внутри тела функции, в котором они объявлены. При завершении выполнения

26.8. Условные переменные

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

Условные выражения

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

Функции и переменные. Локальные переменные

Функции и переменные. Локальные переменные Объявленные ранее функции создают внутри своего тела собственные переменные. Это так называемые локальные переменные. Такие переменные доступны только внутри тела функции, в котором они объявлены. При завершении выполнения

ГЛАВА 7 Взаимные исключения и условные переменные

ГЛАВА 7 Взаимные исключения и условные переменные 7.1. Введение Эта глава начинается с обсуждения синхронизации — принципов синхронизации действий нескольких программных потоков или процессов. Обычно это требуется для предоставления нескольким потокам или процессам

7.5. Условные переменные: ожидание и сигнализация

7.5. Условные переменные: ожидание и сигнализация Взаимное исключение используется для блокирования, а условная переменная — для ожидания. Это два различных средства синхронизации, и оба они нужны. Условная переменная представляет собой переменную типа pthread_cond_t. Для

7.6. Условные переменные: время ожидания и широковещательная передача

7.6. Условные переменные: время ожидания и широковещательная передача В обычной ситуации pthread_cond_signal запускает выполнение одного потока, ожидающего сигнал по соответствующей условной переменной. В некоторых случаях поток знает, что требуется пробудить несколько других

Условные операторы If .. Then.

Условные операторы If .. Then. Условные операторы If. . .Then, а также их вариации If. . .Then. . .Else и If. . .ElseIf используются значительно чаще любых других операторов. Довольно часто операторы If. . .Then встречаются и в других главах, но в этой они уж точно в центре внимания. Основная форма

4.4.6. Сигнальные (условные) переменные

4.4.6. Сигнальные (условные) переменные Мы узнали, как с помощью исключающего семафора защитить переменную от одновременного доступа со стороны двух и более потоков и как посредством обычного семафора реализовать счетчик обращений, доступный нескольким потокам.

Условные выражения

Условные выражения Условное выражение позволяет нам выполнить одно из двух входящих в него выражений в зависимости от выполнения или невыполнения какого-либо условия. Существует также другая, «вырожденная» разновидность условного выражения, содержащая только одно

Источник

Оцените статью
Adblock
detector