Я пишу слой абстракции для связанных с потоками функций в C-проекте. Не все платформы, для которых может быть построен код, поддерживают многопоточность; альтернативы доступны для этих платформ.
Заголовочный файл определяет макрос препроцессора, если поддерживается многопоточность, поэтому условные выражения препроцессора могут использоваться для включения и отключения блоков кода, которые требуются только при многопоточности (или только без).
Функции - это тонкие обертки вокруг их собственных реализаций, которые могут отличаться от платформы к платформе. Типы сопоставляются с соответствующими нативными типами с помощью
#define mythread pthread_t
и аналогичные.
Во избежание необходимости загромождать код условными кодами каждый раз, когда необходимо получить или снять блокировку, большинство функций можно вызывать даже в однопоточных сборках, что делает их недоступными. Поэтому условия необходимы только при порождении или присоединении нитей или для их заменителей. (Попытка вызова функции создания потока в однопоточной сборке приведет к ошибке компилятора.)
Это также означает, что абстрагированные типы потоков должны сопоставляться с чем-либо, даже если потоки не поддерживаются, поскольку могут существовать локальные переменные этих типов (опять же, чтобы не загромождать код условными выражениями). Пока что я сопоставляю их с void
в однопоточных сборках, например:
#ifdef HAVE_POSIX_THREADS
#define mythread pthread_t
#else
#ifdef HAVE_FUNKY_THREADS
#define mythread FThread
#else /* no supported native thread API available, single-threaded build */
#define mythread void
#endif
Это, однако, происходит за счет невозможности использовать объявления вроде:
mythread new_thread;
(который объявил бы переменную void
, недопустимую в C). Эту проблему можно обойти, работая только с указателями на эти типы - фактически каждая функция, которая инициализирует любой из этих типов, выделяет память и возвращает указатель на нее.
Вопрос : Мне было интересно, есть ли более элегантный способ для подобных ситуаций.