TGViewer
Евгений Козлов пишет про IT Евгений Козлов пишет про IT @careerunderhood · 2.83K subscribers
Post #408 1.65K
Concurrency, Synchronization and Consistency. Пост №12. Реентерабельность (Reentrancy).

Еще немного экзотики языка С. С этим понятием я сам познакомился буквально в прошлом году, когда готовил прошлый цикл постов. В универе о таком не рассказывали (либо я забыл) а в работе не сталкивался. Тем не менее опытные программисты на C и C++ наверняка знают о нем и так или иначе учитывают его в системном программировании. Это понятие относится не только к конкуррентному программированию но и последовательному. Начнем с определения.

Реентерабельность (reentrancy) - свойство функции, при котором её можно безопасно вызывать повторно, даже если предыдущее выполнение ещё не закончилось.

Пример функции из стандартной библиотеки С strtok - классической нереентерабельной функции:
#include <stdio.h>
#include <string.h>

int main(void) {
char str[] = "one two three four";
const char *delim = " "; // разделитель — пробел

char *token = strtok(str, delim);
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, delim); // продолжаем с того места, где остановились
}

return 0;
}


Вывод:
one
two
three
four

Почему функция нереентерабельная? Она внутри себя хранит статическую переменную - состояние строки. Обратите внимание на код, в цикле мы не передаем ничего кроме разделителя то есть функция "запомнила" нашу строку.

Думаю вы догадались, использование такой функции для нескольких строк вызовет проблемы:
#include <stdio.h>
#include <string.h>

int main() {
char str1[] = "one,two,three";
char str2[] = "alpha,beta,gamma";

char *token;

token = strtok(str1, ",");
printf("%s\n", token);

token = strtok(str2, ",");
printf("%s\n", token);

// продолжение парсинга первой строки сломано
token = strtok(NULL, ",");
printf("%s\n", token);
}

Вывод:
one
alpha
beta

Наверняка вы как и я словили недоумение. Зачем в стандартной библиотека языка функцию реализовали через внутренний статический буфер? Ответ простой - C создавался в 70-х, задолго до эпохи повсеместных многопроцессорных систем / multithreading и гигабайтных оперативок. Тогда:
- память была ограничена;
- скорость была критична;
- программы были однопоточными.

Когда компьютеры стали мощнее, появились примитивы многопоточности встал вопрос - как писать код, с такими то библиотечными функциями? Ответ - создание реентерабельных функций - аналогов.

Пример кода для strtok_r - реентерабельной реализации strtok. Она не хранит внутреннего состояния, её поведение регулируется аргументами, можно вызывать из нескольких потоков и все будет работать корректно.
#include <stdio.h>
#include <string.h>

int main(void) {
char s1[] = "one,two,three";
char s2[] = "alpha,beta,gamma";

char *save1 = NULL;
char *save2 = NULL;

char *t1 = strtok_r(s1, ",", &save1);
printf("s1: %s\n", t1);

char *t2 = strtok_r(s2, ",", &save2);
printf("s2: %s\n", t2);

t1 = strtok_r(NULL, ",", &save1);
printf("s1: %s\n", t1);

t2 = strtok_r(NULL, ",", &save2);
printf("s2: %s\n", t2);

t1 = strtok_r(NULL, ",", &save1);
printf("s1: %s\n", t1);

t2 = strtok_r(NULL, ",", &save2);
printf("s2: %s\n", t2);

printf("s1: %s\n", strtok_r(NULL, ",", &save1));
printf("s2: %s\n", strtok_r(NULL, ",", &save2));

return 0;
}

Вывод:
s1: one
s2: alpha
s1: two
s2: beta
s1: three
s2: gamma
s1: (null)
s2: (null)


Обратите внимание на аргументы - теперь функция принимает буфер, чтобы ответственность за работу с памятью взял на себя программист. Хочешь простой код? Аллоцируй на каждый вызов функции новый буфер и не парься. Хочешь меньше аллокаций? Делай единый буфер, защищай его примитивом синхронизации если пишешь многопоточную программу.

Большая сила - большая ответственность👨‍🦳

Спасибо за то что читали, задавайте вопросы, рассказывайте сталкивались ли с реентерабельностью в работе. Поправляйте, дополняйте меня если что то упустил.
  • 👍 11
  • ❤ 4
  • 🔥 4
More from @careerunderhood
  1. Oct 2, 2026Пока от темы Concurrency далеко не ушли. В последнем цикле я если и упоминал вопросы произ…
  2. Sep 30, 2026Результаты опроса меня впечатлили. Большинству интересны истории из работы. Поехали, начне…
  3. Sep 25, 2026Post #470
  4. Sep 21, 2026Concurrency, Synchronization and Consistency. Non-blocking. Оглавление Введение - Блокирую…
  5. Sep 21, 2026Concurrency and Consistency. Non-blocking, lock-free and async. Пост №12. Заключение. Когд…
  6. Sep 20, 2026Concurrency and Consistency. Non-blocking, lock-free and async. Пост №11. Самые важные фак…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →