Em geral, presumo que os fluxos não estão sincronizados, cabe ao usuário fazer o bloqueio apropriado. No entanto, coisas como cout
receber tratamento especial na biblioteca padrão?
Ou seja, se vários threads estiverem gravando, cout
eles podem corromper o cout
objeto? Eu entendo que, mesmo se sincronizado, você ainda terá uma saída intercalada aleatoriamente, mas essa intercalação é garantida. Ou seja, é seguro usar a cout
partir de vários threads?
Este fornecedor é dependente? O que o gcc faz?
Importante : forneça algum tipo de referência para sua resposta se você disser "sim", pois preciso de algum tipo de prova disso.
Minha preocupação também não é com as chamadas de sistema subjacentes, elas estão bem, mas os fluxos adicionam uma camada de buffer no topo.
printf
brilha, pois a saída completa é gravada destdout
uma só vez; ao usarstd::cout
cada elo da cadeia de expressão seria enviado separadamente parastdout
; entre eles pode haver algum outro thread de gravaçãostdout
devido ao qual a ordem da saída final fica confusa.Respostas:
O padrão C ++ 03 não diz nada sobre isso. Quando você não tem garantias sobre a segurança de thread de algo, deve tratá-la como não segura de thread.
De particular interesse aqui é o fato de que
cout
é armazenado em buffer. Mesmo se as chamadas parawrite
(ou seja lá o que for que realize esse efeito naquela implementação particular) tenham garantia de serem mutuamente exclusivas, o buffer pode ser compartilhado por diferentes threads. Isso levará rapidamente à corrupção do estado interno do fluxo.E mesmo que o acesso ao buffer seja seguro para thread, o que você acha que acontecerá neste código?
Você provavelmente deseja que cada linha aqui atue em exclusão mútua. Mas como uma implementação pode garantir isso?
No C ++ 11, temos algumas garantias. O FDIS diz o seguinte em §27.4.1 [iostream.objects.overview]:
Portanto, você não obterá fluxos corrompidos, mas ainda precisará sincronizá-los manualmente se não quiser que a saída seja lixo.
fonte
cout.sync_with_stdio()
seja verdade, usarcout
para gerar caracteres de vários threads sem sincronização adicional está bem definido, mas apenas no nível de bytes individuais. Assim,cout << "ab";
ecout << "cd"
executado em threads diferentesacdb
pode gerar saída , por exemplo, mas não pode causar comportamento indefinido.Esta é uma grande pergunta.
Primeiro, C ++ 98 / C ++ 03 não tem o conceito de "thread". Portanto, naquele mundo, a pergunta não tem sentido.
E sobre C ++ 0x? Veja a resposta do Martinho (que admito que me surpreendeu).
Que tal implementações específicas pré-C ++ 0x? Bem, por exemplo, aqui está o código-fonte
basic_streambuf<...>:sputc
do GCC 4.5.2 (cabeçalho "streambuf"):Claramente, isso não executa nenhum bloqueio. E nem mesmo
xsputn
. E esse é definitivamente o tipo de streambuf que cout usa.Até onde eu posso dizer, libstdc ++ não executa nenhum bloqueio em qualquer uma das operações de fluxo. E eu não esperava nenhum, pois seria lento.
Portanto, com essa implementação, obviamente, é possível que a saída de duas threads se corrompa ( não apenas intercale).
Este código pode corromper a própria estrutura de dados? A resposta depende das possíveis interações dessas funções; por exemplo, o que acontece se uma thread tenta liberar o buffer enquanto outra tenta chamar
xsputn
ou algo assim. Pode depender de como o compilador e a CPU decidem reordenar as cargas e armazenamentos de memória; seria necessária uma análise cuidadosa para ter certeza. Também depende do que sua CPU faz se dois threads tentam modificar o mesmo local simultaneamente.Em outras palavras, mesmo que funcione bem em seu ambiente atual, ele pode falhar quando você atualiza seu tempo de execução, compilador ou CPU.
Resumo executivo: "Eu não faria". Crie uma classe de registro que faça o bloqueio adequado ou mude para C ++ 0x.
Como uma alternativa fraca, você pode definir cout como sem buffer. É provável (embora não garantido) que ignoraria toda a lógica relacionada ao buffer e chamaria
write
diretamente. Embora isso possa ser proibitivamente lento.fonte
cout
.www.techrepublic.com/article/use-stl-streams-for-easy-c-plus-plus-thread-safe-logging
e também: Os fluxos de saída padrão em C ++ thread-safe (cout, cerr, clog)?
ATUALIZAR
Dê uma olhada na resposta de @Martinho Fernandes para saber o que o novo padrão C ++ 11 fala sobre isso.
fonte
Como outras respostas mencionam, isso é definitivamente específico do fornecedor, já que o padrão C ++ não faz menção a threading (isso muda em C ++ 0x).
O GCC não faz muitas promessas sobre segurança de thread e E / S. Mas a documentação para o que ele promete está aqui:
o principal é provavelmente:
Não sei se algo mudou desde o cronograma 3.0 mencionado.
A documentação de segurança de thread do MSVC para
iostreams
pode ser encontrada aqui: http://msdn.microsoft.com/en-us/library/c9ceah3b.aspx :Observe que essas informações são para a versão mais recente do MSVC (atualmente para o VS 2010 / MSVC 10 /
cl.exe
16.x). Você pode selecionar as informações para versões mais antigas do MSVC usando um controle suspenso na página (e as informações são diferentes para versões mais antigas).fonte