2013-04-11 8 views
10

consideri il seguente programma C banale,Qual è il modo corretto per creare una libreria C multi-piattaforma e sicura per i thread?

#include <errno.h> 
int 
main(int argc, char* argv[]) { 
    return errno; 
} 

Quando compilato su Solaris, il comportamento di questo codice è dipendente dalla presenza di -D_REENTRANT.

solaris$ cc -E test.c | grep return 
    return errno; 
solaris$ cc -D_REENTRANT -E test.c | grep return 
    return (* (___errno ())); 

con quest'ultima versione essendo thread-safe. Se si compila lo stesso codice su Linux, si ottiene lo stesso comportamento indipendente -D_REENTRANT

linux$ gcc -E test.c | grep return 
    return (*__errno_location()); 
linux$ gcc -D_REENTRANT -E test.c | grep return 
    return (*__errno_location()); 

Solaris' cc ha l'opzione -mt, che implica -D_REENTRANT, come fa gcc 's -pthread. Tuttavia, per una libreria, la scelta di queste opzioni multi-thread sembra scadente, poiché inietta una dipendenza non necessaria dal runtime di threading. Tuttavia, se la libreria ha bisogno di essere thread-safe (incluso errno), allora la semantica thread-safe è necessaria sia in fase di compilazione della libreria che del codice derivante. Su Linux, questo è facile, perché errno è sempre thread-local, ma ciò non è garantito su altri sistemi come appena dimostrato.

Ciò si traduce nella domanda: in che modo una libreria thread-safe è correttamente compilata e distribuita con le intestazioni? Un'opzione potrebbe essere #define _REENTRANT nell'intestazione principale, ma ciò potrebbe causare problemi se si verifica #include <errno.h> prima dell'inclusione dell'intestazione della libreria. Un'altra opzione è compilare la libreria con -D_REENTRANT e avere l'intestazione principale #error se _REENTRANT non è definita.

Qual è il modo corretto/migliore per creare una libreria sicura per i thread e assicurarsi che interagisca correttamente con il codice a cui è collegato?

risposta

4

Al momento non ho accesso a nessuna macchina Solaris, quindi non posso verificarlo. Ma cosa succede quando inserisci #define _POSIX_C_SOURCE 200112L come prima riga in test.c (prima dell'inserimento di <errno.h>)? Se Solaris è conforme a POSIX, è necessario che lo errno si espanda alla versione thread-safe. Questo perché POSIX definisce errno come qui sotto:

Per ciascun thread di un processo, il valore di errno non è condizionata da chiamate di funzione o assegnazioni di errno da altri thread.

Di conseguenza, questo è portatile per qualsiasi sistema conforme a POSIX. Infatti, se si desidera scrivere un codice applicativo conforme a POSIX, è necessario immettere _POSIX_C_SOURCE al valore appropriato per la versione minima di POSIX che si sta prendendo di mira. La definizione dovrebbe essere nella parte superiore di ogni file sorgente prima di includere eventuali intestazioni. Dalla versione 2001 dello standard:

Un'applicazione POSIX rigorosamente conforme è un'applicazione che richiede solo le funzionalità descritte in IEEE Std 1003.1-2001. Tale domanda:

...

8.Per il linguaggio di programmazione C, definisce _POSIX_C_SOURCE essere 200112L prima di ogni intestazione è incluso

+0

'cc -D_POSIX_C_SOURCE = 200112L -E test.c | grep return -> return (* (___errno())); ' In effetti, funziona come previsto; stai anche raccomandando di definirlo nell'intestazione della libreria compatibile con POSIX? –

+0

@AlexanderChernyakhovsky: No, non ha mai bisogno di essere definito in qualsiasi file di intestazione. Dovrebbe essere sempre definito nella parte superiore dei file sorgente. Questo è l'unico modo per essere sicuri che sia definito prima di includere qualsiasi intestazione. Puoi anche definirlo sulla riga di comando, come hai fatto nel tuo esempio. È accettabile Preferisco vederlo nel file sorgente, ma in parte è solo questione di gusti. –

+0

Interessante. Sembra che tu stia sostenendo di controllare ancora un '# define' nella mia intestazione della libreria, perché non voglio che uno sviluppatore finale finisca per ottenere l'errno sbagliato. –

0

Se la libreria usa autoconf, probabilmente si desidera utilizzare il AC_USE_SYSTEM_EXTENSIONS macro. Quella macro imposta alcune definizioni specifiche per target che abilitano la semantica delle estensioni POSIX +. Al momento non ho un sistema Solaris da testare, ma credo che _POSIX_PTHREAD_SEMANTICS dovrebbe abilitare l'errno thread-safe. Almeno abilita le funzioni POSIX _r() invece delle varianti POSIX-draft _r() che Solaris fornisce in modo fastidioso di default.

Problemi correlati