pthread_cond_wait по сравнению с семафором

Когда вы объявляете ссылочную переменную (т. е. объект), вы действительно создаете указатель на объект. Рассмотрим следующий код, в котором вы объявляете переменную примитивного типа int:

int x;
x = 10;

В этом примере переменная x является int, и Java инициализирует ее для 0. Когда вы назначаете его 10 во второй строке, ваше значение 10 записывается в ячейку памяти, на которую указывает x.

Но когда вы пытаетесь объявить ссылочный тип, произойдет что-то другое. Возьмите следующий код:

Integer num;
num = new Integer(10);

Первая строка объявляет переменную с именем num, но она не содержит примитивного значения. Вместо этого он содержит указатель (потому что тип Integer является ссылочным типом). Поскольку вы еще не указали, что указать на Java, он устанавливает значение null, что означает «Я ничего не указываю».

Во второй строке ключевое слово new используется для создания экземпляра (или создания ) объекту типа Integer и переменной указателя num присваивается этот объект. Теперь вы можете ссылаться на объект, используя оператор разыменования . (точка).

Exception, о котором вы просили, возникает, когда вы объявляете переменную, но не создавали объект. Если вы попытаетесь разыменовать num. Перед созданием объекта вы получите NullPointerException. В самых тривиальных случаях компилятор поймает проблему и сообщит вам, что «num не может быть инициализирован», но иногда вы пишете код, который непосредственно не создает объект.

Например, вы можете имеют следующий метод:

public void doSomething(SomeObject obj) {
   //do something to obj
}

В этом случае вы не создаете объект obj, скорее предполагая, что он был создан до вызова метода doSomething. К сожалению, этот метод можно вызвать следующим образом:

doSomething(null);

В этом случае obj имеет значение null. Если метод предназначен для того, чтобы что-то сделать для переданного объекта, целесообразно бросить NullPointerException, потому что это ошибка программиста, и программисту понадобится эта информация для целей отладки.

Альтернативно, там могут быть случаи, когда цель метода заключается не только в том, чтобы работать с переданным в объекте, и поэтому нулевой параметр может быть приемлемым. В этом случае вам нужно будет проверить нулевой параметр и вести себя по-другому. Вы также должны объяснить это в документации. Например, doSomething может быть записано как:

/**
  * @param obj An optional foo for ____. May be null, in which case 
  *  the result will be ____.
  */
public void doSomething(SomeObject obj) {
    if(obj != null) {
       //do something
    } else {
       //do something else
    }
}

Наконец, Как определить исключение & amp; причина использования Трассировки стека

46
задан dragosht 14 December 2015 в 12:21
поделиться

4 ответа

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

условная переменная А является более прощающей в некотором отношении. Можно, например, использовать cond_broadcast для пробуждения всех официантов без производителя, знающего, сколько существует. И если Вы cond_signal condvar ни с кем ожидающим на нем тогда ничего не происходит. Это хорошо, если Вы не знаете, будет ли там заинтересованным слушателем. Это также, почему слушатель должен всегда проверять состояние со взаимным исключением, сохраненным прежде, чем ожидать - если они не делают тогда, они могут пропустить сигнал и не проснуться вплоть до следующего (который никогда не мог быть).

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

Это является очень непростым действительно для попытки этого вида вещи со взаимным исключением и семафором. Проблема возникает, когда Вы хотите взять взаимное исключение, проверьте некоторое состояние, затем ожидайте на семафоре изменений. Если Вы не можете атомарно выпустить взаимное исключение и ожидать на семафоре (который в pthreads Вы не можете), Вы заканчиваете тем, что ожидали на семафоре при содержании взаимного исключения. Это блокирует взаимное исключение, означая, что другие не могут взять его для внесения изменения, о котором Вы заботитесь. Таким образом, Вы испытаете желание добавить другое взаимное исключение способом, которое зависит от Ваших конкретных требований. И возможно другой семафор. Результатом является вообще неправильный код с вредными условиями состязания.

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

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

63
ответ дан Steve Jessop 26 November 2019 в 20:26
поделиться

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

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

Условные переменные также позволяет Вам позволять весь потоки, ожидающие на условной переменной для продолжения через [1 112]. Дополнительно это также позволяет, Вы для выполнения синхронизированный ожидаете , таким образом, Вы не заканчиваете тем, что ожидали навсегда.

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

20
ответ дан Nisse Engström 26 November 2019 в 20:26
поделиться

2-й отрывок является колоритным, не делайте этого.

другие ответы имеют хорошее обсуждение относительных достоинств; я просто добавлю, что pthread_cond_broadcast ясное преимущество условных переменных.

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

Действительно, в 2-м отрывке у Вас нет блокировки, защищающей чтение бегунка-> состояние, таким образом, к этому получают доступ через гонку данных. Большинство платформ позволит Вам сойти с рук это в этом конкретном примере, но это имеет неопределенную семантику POSIX и моделью памяти следующих стандартов C/C++.

На самом деле, реальное состояние состязания возможно, если другой поток выделяет новую структуру бегунка и перезаписывает бегунок; поток ожидания мог бы видеть обновление указателя 'бегунка', не видя инициализацию бегунка-> состояние. Действительно, 2-й отрывок напрашивается на неприятности, в этом случае и в целом.

http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/

5
ответ дан Blaisorblade 26 November 2019 в 20:26
поделиться

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

В целом, состояние Вы - waintin на, может быть полностью выражен семафором, тогда можно использовать просто это. Структура блокировки меньше в размере, и это требует, чтобы меньше атомарных операций проверило/установило/выпустило.

Иначе, если состояние является сложными, и различными частями кода, ожидают на различных условиях той же переменной (например, здесь Вы хотите x< 10; там Вы хотите y> x), используете cond_wait.

0
ответ дан Javier 26 November 2019 в 20:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: