Я пишу библиотеку параллельных транзакций на 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
использовать не обязательно :).