2009-06-03 11 views
0

J'écris une bibliothèque de transactions simultanées dans C et trouve le problème suivant. Considérons un membre de transaction échantillon pseudo-code, où la « transaction » représente un canal de communication avec le maître de la transaction:Comment simuler des exceptions en C avec goto?

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"); 
} 

Dans les transactions simultanées, nous pouvons voter que si on nous demande le vote par le maître. Toutefois, le maître peut appeler trans_abort(member) à tout moment, ce qui oblige le membre spécifié à annuler la transaction. Le message ABORT peut être reçu par le membre à n'importe quel stade d'exécution et dans ce cas, il ne doit pas attendre que l'exécution atteigne l'appel trans_ready(). Par exemple, s'il y a un appel trans_rcv() dans le code suivant, le processus attendrait les données du maître qui ne seront jamais envoyées.

Maintenant, le point. J'ai déjà le code pour enregistrer la fonction d'annulation qui annule les changements, mais j'aimerais aussi avoir un mécanisme supplémentaire qui permettrait d'ignorer le reste des opérations restantes et de passer directement au code de vote. J'ai une idée d'utiliser goto ici pour simuler des exceptions:

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

... 

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

Cependant, l'écriture ifs pour chaque appel de trans_rcv ou trans_send n'est pas très confortable, surtout si le code de transaction est complexe. Avez-vous une idée d'une meilleure solution ou est-ce le seul moyen? Il n'a pas à utiliser goto, en passant :).

+0

Voyons combien de personnes viendront avec quelque chose comme "goto? AAAAAAAAAAAAARGH": P –

+0

goto? AAAAAAAAAAAAARGH –

Répondre

5

Si la saisie des Ifs est le problème, vous pouvez utiliser une macro, comme:

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

Si trans_rcv a des paramètres, cela devrait fonctionner (en gcc, au moins):

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

Macros ... comme je les ai oubliés. Merci d'avance! – Zyx

+2

Assurez-vous d'envelopper le si dans un do alors que faux. Cela vous appelez trans_rcv_CHK avec un point-virgule à la fin et ne pas avoir de conséquences inattendues. Voir: http://c2.com/cgi/wiki/Wiki?TrivialDoWhileLoop –

+1

@sharth: bon point, merci. J'ai ajouté la boucle à la réponse. – tsg

3

Personnellement, je coderais cela en utilisant une boucle while avec une machine à états basée sur un switch.

7

goto fonctionne uniquement à l'intérieur d'une fonction, ce qui est probablement trop une limitation pour le mécanisme d'exception. Je suggère d'utiliser setjmp/longjmp fonctions - voir Wikipedia pour plus de détails.

3

Une des meilleures sources pour exception handling in C. Fondamentalement, comment les gens à RTOS mis en œuvre des exceptions pour leur module RTFile. Méfiez-vous du glissement terrible dans la langue de l'assemblée passé la deuxième moitié de l'article.