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?
'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? –
@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. –
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. –