Как имитировать исключения в C с помощью goto?

Я пишу библиотеку параллельных транзакций на C и обнаружил следующую проблему. Рассмотрим пример псевдокода члена транзакции, где «транзакция» представляет собой канал связи с мастером транзакции:

transaction = trans_join();

do_some_ops();

/* receive the data from the master */
trans_rcv(transaction, data);

do_some_ops();

trans_send(transaction, answer);

/* wait for the possibility for voting */
trans_ready(transaction);

/* vote for commiting and wait for the voting results. */
if(trans_commit(answer))
{
   printf("Final commiting the changes.\n");
}
else
{
   printf("Rolling back the changes.\n");
}

В параллельных транзакциях мы можем голосовать только в том случае, если мастер запрашивает голосование. Однако мастер может вызвать trans_abort(member) в любое время, вынуждая указанного члена отменить транзакцию. Сообщение ABORT может быть получено участником на любой стадии выполнения, и в этом случае он не должен ждать, пока выполнение достигнет trans_ready() вызова. Например, если в более позднем коде есть вызов trans_rcv(), процесс зависнет, ожидая данных от мастера, которые никогда не будут отправлены.

Теперь по делу. У меня уже есть код для регистрации функции прерывания, которая откатывает изменения, но я также хотел бы иметь дополнительный механизм, который позволил бы пропустить остальные оставшиеся операции и сразу перейти к коду голосования. У меня есть идея использовать здесь goto для имитации исключений:

if(!trans_rcv()) /* fail, we received the abort message */
{
   goto abort_code;
}

...

abort_code:
trans_ready(transaction);
/* etc. */

Однако писать ifs для каждого вызова trans_rcv или trans_send не очень удобно, особенно если код транзакции сложный. У вас есть идеи по поводу лучшего решения или это единственный способ? Кстати, goto использовать не обязательно :).


person Zyx    schedule 03.06.2009    source источник
comment
посмотрим, сколько людей придут с чем-то вроде goto? AAAAAAAAAAAAARGH: P   -  person Andrea Ambu    schedule 03.06.2009


Ответы (5)


Если проблема заключается в вводе IF, вы можете использовать макрос, например:

#define trans_rcv_CHK do { \
     if (!trans_rcv()) \
     { \
          goto abort_code; \
     } \
} while(0)

Если у trans_rcv есть параметры, это должно работать (по крайней мере, в gcc):

#define trans_rcv_CHK(...) do { \
     if (!trans_rcv(__VA_ARGS__)) \
     { \
          goto abort_code; \
     } \
} while (0)
person tsg    schedule 03.06.2009
comment
Макросы ... как странно я о них забыл. Заранее спасибо! - person Zyx; 03.06.2009
comment
Убедитесь, что вы заключили if в do while false. Это позволит вам вызывать trans_rcv_CHK с точкой с запятой в конце и избежать непредвиденных последствий. См .: c2.com/cgi/wiki/Wiki?TrivialDoWhileLoop - person Bill Lynch; 03.06.2009

goto работает только внутри одной функции, что, вероятно, является слишком большим ограничением для механизма исключения.

Я бы предложил использовать _2 _ / _ 3_ функции - подробности см. В Википедии.

person qrdl    schedule 03.06.2009

Лично я бы закодировал это, используя цикл while с конечным автоматом внутри него.

person ChrisBD    schedule 03.06.2009

Один из лучших источников для обработки исключений в C. В основном, как люди в RTOS реализовали исключения для своего модуля RTFile. Остерегайтесь ужасного промаха на ассемблере после второй половины статьи.

person diapir    schedule 03.06.2009

См. Статью Hanson «Интерфейсы и реализации C: методы создания программного обеспечения многократного использования». Он предоставляет механизм исключений, основанный на setjmp() и longjmp(). Код доступен с лицензией MIT.

person Jonathan Leffler    schedule 03.06.2009