Newsgroup: it.comp.lang.c++
Titolo: Atomicita` degli stream

In un thread di qualche mese fa su icl.c++ che parlava di librerie di 
logging si era arrivati a parlare dell'atomicita` degli stream garantita 
da posix... beh l'atomicita` in quel caso si riferisce agli stream posix 
appunto (FILE *), non certo a std::cerr e std::cout, ho visto di recente 
in un'applicazione su macchina multicore che gli stream c++ si mescolano 
"allegramente", e, almeno con il GCC, non sono riuscito ad evitare la 
cosa e sono passato all'uso di fprintf su stderr invece di cerr...
Ecco un piccolo esempio che mostra il problema:
#include <iostream>
#include <pthread.h>
void *mythread(void *v) {
     int val_ = (int)v;
     for (int i = 0; i < 10; i++) {
         std::cerr << i << ')' << val_ << " " << val_ << " " << val_ << 
" " << val_ << " " << val_ << 'e' << std::endl;
         sleep(1);
     }
     return NULL;
}
int main()
{
     for (int i = 0; i < 10; ++i) {
         pthread_t temp;
         pthread_create(&temp, NULL, mythread, (void *)i);
     }
     sleep(20);
}
L'output generato e` il seguente sia su linux che su solaris (potrebbe 
esser necessario lanciarlo + di una volta per triggare il problema):
0)0 0 0 0 0e
0)1 1 1 1 1e
0)2 0)3 3 3 3 30)5 5 5 5 5e
0)7 70)4 4 4 4 4e
00)6 6 6 6 6e
e
0)8 8 8 8 8e
  7 7 7e
)9 9 9 9 9e
2 2 2 2e
1)0 0 0 0 0e
1)1 1 1 1 1e
1)5 5 5 5 5e
1)4 4 4 4 4e
1)6 6 61)3 3 3 3 3e
  6 6e
1)8 8 8 8 8e
1)7 7 7 7 7e
1)2 2 2 2 2e
1)9 9 9 9 9e

         sleep(1);
Capitato anche a me.
Potresti provare con qualcosa del tipo:
std::cerr<<(boost::lexical_cast<std::string>(i)+')'+
boost::lexical_cast<std::string>(val_)+" "+
boost::lexical_cast<std::string>(val_)+ " "+
boost::lexical_cast<std::string>(val_)+ " "+
boost::lexical_cast<std::string>(val_)+" "+
boost::lexical_cast<std::string>(val_)+'e\n');
N.B. Probabilmente e' meno efficiente e non fa il flush alla fine.
Altrimenti io ho risolto creando un oggetto proxy che punta ad uno 
stream ed un mutex (statici).
Quando istanziato acquisisce il lock, poi lo usi come se fosse lo stream 
stesso ed infine, alla distruzione, rilascia il lock.
Il limite e' che devi passare sempre da quello; infatti se usi std::cerr 
direttamente, salti questo meccanismo e torni al problema di prima.
  bye
	av.

 [...]
Manlio Perillo

 sistemi operativi.
Qui ci sono simpatiche funzioni non starndard per Linux e Solarix:
http://www.gnu.org/software/libtool/manual/libc/Streams-and-Threads.html
Poi perché:
  stream << stringa_a << stringa_b;
dovrebbe essere atomica?
Prima scrive la stringa a, poi la stringa b. Oppure tutte insieme. 
Oppure non scrive niente e rimane tutto in un buffer interno. Lo 
standard parla di *garanzie* su codice simile?
-- 
Articolo 33 della Costituzione italiana: L'arte e la scienza sono 
libere e libero ne è l'insegnamento.
Se siete tosti: 
http://www.rexresearch.com/kervran/kervran.htm

 standard parla di *garanzie* su codice simile?
Lo standard per il C non parla di atomicità, dato che non descrive/
supporta ambienti multiprocesso, per non parlare di ambienti multi thread.
POSIX invece parla di atomicità solo per l'IO "diretto" su PIPE e FIFO 
(ma la documentazione della read, letta ora, parla di atomicità anche per 
file regolari, boh), e garantisce che le operazioni sugli stream C siano 
thread safe.
Nel l'esempio che fai, lo standard del C++ garantisce che venga 
"scritta" (ammesso si possa usare questo verbo) prima stringa_a e poi 
stringa_b, ma non dice niente di quello che succede sul file sottostante.
Quel che è certo (?) è che viene scritto prima stringa_a e poi stringa_b, 
ma non sai che succede se un altro processo sta scrivendo sullo stesso 
file (per non parlare di un altro thread che nel frattempo cambia la 
posizione corrente del file tra le due operazioni).
E, tra l'altro, dato che C++ non supporta i thread, e dato che POSIX non 
supporta C++, non sai nemmeno se la scrittura sugli stream C++ sia thread 
safe.
Manlio Perillo

 safe.
La cosa divertente è che uno per lavorare ha bisogno di tutte e due le 
cose. Lo standard C++ per potere cambiare compilatore senza dovere 
cambiare una riga di codice o peggio impararsi un dialetto nuovo, e lo 
standard POSIX per cambiare piattaforma senza cambiare codice.
Capisco poi che uno magari ha bisogno della caratteristica speciale del 
compilatore X e della piattaforma Y.
Resta il fatto che viviamo in un mondo difficile quanto a standard.


 Resta il fatto che viviamo in un mondo difficile quanto a standard.
Come ho sentito dire da Herb Sutter, la cosa bella degli standard è
che ce n'è così tanti tra cui scegliere...
Ciao,
Nicola