Это не потокобезопасно. Чтобы продемонстрировать это, предположим, что поток A вызывает min (1,2), а threadB - min (3,4). Предположим, что поток A выполняется первым и прерывается планировщиком прямо у вопросительного знака макроса, поскольку его временной интервал истек.
Тогда x_GLOB равен 1, а y_GLOB равен 2.
Теперь предположим, что threadB работает некоторое время и завершает содержимое макроса:
x_GLOB равно 3, y_GLOB равно 4.
Теперь предположим, что threadA возобновляется. Он вернет x_GLOB (3) вместо правильного ответа (1).
Очевидно, я немного упростил вещи - прерывание "под знаком вопроса" довольно сложное, и threadA не обязательно возвращает 3, в некоторых компиляторах с некоторыми уровнями оптимизации он может хранить значения в регистрах и не читать обратно из x_GLOB вообще. Таким образом, выдаваемый код может работать с этим компилятором и опциями. Но, надеюсь, мой пример имеет значение - вы не можете быть уверены.
Я рекомендую вам написать статическую встроенную функцию. Если вы пытаетесь быть очень портативным, сделайте это так:
#define STATIC_INLINE static
STATIC_INLINE int min_func(int x, int y) { return x < y ? x : y; }
#define min(a,b) min_func((a),(b))
Тогда, если у вас есть проблемы с производительностью на какой-то конкретной платформе, и это происходит из-за того, что компилятору не удается встроить ее, вы можете беспокоиться о том, нужно ли на этом компиляторе определять STATIC_INLINE по-другому (static inline
в C99 или static __inline
для Microsoft, или что-то еще), или, возможно, даже реализует макрос min
по-другому. Этот уровень оптимизации («он встроен?») - это не то, что вы можете сделать с помощью переносимого кода.