Можно ли определить функциональный макрос с переменным телом? - PullRequest
8 голосов
/ 27 октября 2010

Я искал документы GCC для определения макросов, и похоже, что то, что я хочу, не возможно, но я полагаю, что если это так, кто-то здесь узнает.

Что я хочу сделать, это определить этот макрос:

synchronized(x) {
  do_thing();
}

, который расширяется до:

{
    pthread_mutex_lock(&x);
    do_thing();
    pthread_mutex_unlock(&x);
}

В C ++ я мог бы просто создать SynchronizedBlock объект, который получает блокировку в егоконструктор и разблокирует деструктор, но я понятия не имею, как это сделать на C.

Я понимаю, что мог бы использовать указатель на функцию в виде synchronized(x, &myfunction);, но моя цель - заставить некоторый код на С выглядетькак Java, насколько это возможно.И да, я знаю, что это зло.

Ответы [ 4 ]

16 голосов
/ 28 октября 2010

РЕДАКТИРОВАТЬ : Изменено на версию nategoose

#define synchronized(lock) \
for (pthread_mutex_t * i_#lock = &lock; i_#lock; \
     i_#lock = NULL, pthread_mutex_unlock(i_#lock)) \
    for (pthread_mutex_lock(i_#lock); i_#lock; i_#lock = NULL)

И вы можете использовать это так:

synchronized(x) {
    do_thing(x);
}

Или даже без скоб

synchronized(x)
    do_thing();
4 голосов
/ 27 октября 2010

Вот начало, но вам, возможно, потребуется настроить его:

#define synchronized(lock, func, args...) do { \
    pthread_mutex_lock(&(lock)); \
    func(##args); \
    pthread_mutex_unlock(&(lock)); \
} while (0)

Используйте вот так (к сожалению, не тот Java-подобный синтаксис, который вы хотели):

synchronized(x, do_thing, arg1, arg2);
2 голосов
/ 28 октября 2010

Очень интересный вопрос!

Я посмотрел другие ответы, и мне понравился ответ, использующий for. У меня есть улучшение, если можно! GCC 4.3 представляет макрос COUNTER , который мы можем использовать для генерации уникальных имен переменных.

#define CONCAT(X, Y) X##__##Y
#define CONCATWRAP(X, Y) CONCAT(X, Y)
#define UNIQUE_COUNTER(prefix) CONCATWRAP(prefix, __COUNTER__)

#define DO_MUTEX(m, counter) char counter; \
for (counter = 1, lock(m); counter == 1; --counter, unlock(m))

#define mutex(m) DO_MUTEX(m, UNIQUE_COUNTER(m))

Используя эти макросы, этот код ...

mutex(my_mutex) {
    foo();
}

... расширится до ...

char my_mutex__0;
for (my_mutex__0 = 1, lock(my_mutex); my_mutex__0 == 1; --my_mutex__0, unlock(m)) {
    foo();
}

Когда my_mutex__n начинается с 0 и генерирует новое имя каждый раз, когда оно используется! Вы можете использовать ту же технику для создания похожих на монитор тел кода с уникальным, но неизвестным именем мьютекса.

1 голос
/ 28 октября 2010

Это было лучшее, что я придумал:

#define synchronized(x, things) \
      do { \
           pthread_mutex_t * _lp = &(x); \
           pthread_mutex_lock(_lp);      \
           (things);                     \
           pthread_mutex_unlock(_lp);    \
      } while (0)

...

        synchronized(x,(
                          printf("hey buddy\n"),
                          a += b,
                          printf("bye buddy\n")
                        ));

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

...