Эта статья говорит:
«функция может быть либо повторно, поточно-как, или ни одного.»
Он также говорит:
"Non-возвратные функции являются поточно-небезопасных".
Я вижу, как это может вызвать путаницу. Они означают, что стандартные функции, задокументированные как не обязательные для повторного входа, также не должны быть потокобезопасными, что справедливо для библиотек POSIX iirc (и POSIX заявляет, что это также относится к библиотекам ANSI/ISO, ISO имеет нет концепции потоков и, следовательно, нет концепции безопасности потока). Другими словами, «если функция говорит, что она не реентерабельная, то она говорит, что она тоже небезопасна». Это не логическая необходимость, это просто конвенция.
Вот некоторый псевдокод, который является потокобезопасным (ну, есть много возможностей для обратных вызовов для создания взаимоблокировок из-за блокировки инверсии, но давайте предположим, что документация содержит достаточную информацию для пользователей, чтобы этого избежать), но не повторный вход ,Предполагается, чтобы увеличить глобальный счетчик, а также выполнять функцию обратного вызова:
take_global_lock();
int i = get_global_counter();
do_callback(i);
set_global_counter(i+1);
release_global_lock();
Если обратный вызов снова вызывает эту процедуру, в результате чего в другой функции обратного вызова, то оба уровня обратного вызова получит тот же параметр (который может быть в порядке, в зависимости от API), но счетчик будет только увеличиваться один раз (это почти наверняка не тот API, который вам нужен, поэтому его нужно будет запретить).
Это предположение, что замок является рекурсивным, конечно. Если блокировка нерекурсивна, то, конечно, код не является реентерабельным, так как второй раз не будет работать с блокировкой.
Вот некоторый псевдо-код, который является «слабо Реентрантным», но не поточно-:
int i = get_global_counter();
do_callback(i);
set_global_counter(get_global_counter()+1);
Теперь это прекрасно, чтобы вызвать функцию от обратного вызова, но это не безопасно для вызова функции одновременно из разных потоков. Также небезопасно вызывать его из обработчика сигнала, поскольку повторное включение из обработчика сигнала может также нарушать счет, если сигнал произошел в нужное время. Таким образом, код не является повторным в соответствии с правильным определением.
Вот какой-то код, который, возможно, полностью повторен (за исключением того, что я считаю, что стандарт различает реентерабельный и «не прерываемый по сигналам», и я не уверен, где это падает), но по-прежнему не является потоковым, сейф:
int i = get_global_counter();
do_callback(i);
disable_signals(); // and any other kind of interrupts on your system
set_global_counter(get_global_counter()+1);
restore_signal_state();
на однопоточных приложений, это прекрасно, если предположить, что ОС поддерживает отключение все, что должно быть отключено. Это предотвращает повторное проникновение в критическую точку. В зависимости от того, как отключены сигналы, может быть безопасно звонить из обработчика сигнала, хотя в этом конкретном примере все еще остается проблема параметра, переданного обратному вызову, одинакового для отдельных вызовов. Тем не менее, он все равно может ошибиться в многопоточности.
На практике, не-поточно-безопасный, часто подразумевает неперехват, поскольку (неформально) все, что может пойти не так, из-за прерывания потока планировщиком, а функция, вызванная снова из другого потока, также может если поток прерывается сигналом, и функция снова вызывается из обработчика сигнала. Но тогда «исправление» для предотвращения сигналов (их отключение) отличается от «исправления», чтобы предотвратить параллелизм (обычно блокировки). Это в лучшем случае эмпирическое правило.
Обратите внимание, что здесь я подразумеваю глобальные переменные, но те же соображения применимы, если функция приняла в качестве параметра указатель на счетчик и блокировку. Просто разные случаи были бы небезопасными или неперехватываемыми при вызове с тем же параметром, а не при вызове вообще.
Ваш второй пример не звучит для меня повторно. Если изменение может быть прервано, оставив несогласованное состояние, и в этой точке появляется сигнал, и обработчик для этого сигнала вызывает функцию, тогда, как правило, она идет стрелой. Это проблема повторного входа, а не проблема безопасности потоков. – 2008-12-09 12:22:29