Шрифт:
Последовательность действий потока выглядит следующим образом:
1. Поток запрашивает
2. Неприятность здесь состоит в том, что запросить значение ключа для
3. После этого каждый поток (как создавший ключ, так и использующий его) должен запросить по
4. Дальше поток может работать с собственным экземпляром данных (отдельный экземпляр на каждый поток), используя для доступа к нему
5. При завершении любого потока система уничтожит и его экземпляр данных, вызвав для него деструктор, который был установлен вызовом
Теперь запишем это в коде, заодно трансформировав в новую функцию
To, что типы параметров и возвращаемое значение
Далее следует код
Обратите внимание, что вся описанная техника преобразования потоковых функций в реентерабельные (как и все программные интерфейсы POSIX) отчетливо ориентирована на семантику классического С, в то время как все свое изложение мы ориентируем и иллюстрируем на С++. При создании экземпляра собственных данных полностью разрушается контроль типизации: разные экземпляры потоков вполне могли бы присвоить своим указателям данные (типа v
Особая область, в которой собственные данные потока могут найти применение и где локальные (стековые) переменные потока не могут быть использованы, — это асинхронное выполнение фрагмента кода в контексте потока, например при получении потоком сигнала.
Еще одно совсем не очевидное применение собственных данных потока (мы не встречали в литературе упоминаний о нем), которое особо органично вписывается в использование именно С++, — это еще один способ возврата в родительский поток результатов работы дочерних. При этом неважно, как были определены дочерние потоки - как присоединенные или как отсоединенные (мы обсуждали это ранее); такое использование в заметной мере нивелирует их разницу. Эта техника состоит в том, что: