Secara umum saya berasumsi bahwa aliran tidak disinkronkan, terserah pengguna untuk melakukan penguncian yang sesuai. Namun, apakah hal-hal seperti cout
mendapat perlakuan khusus di perpustakaan standar?
Artinya, jika beberapa utas menulis, cout
dapatkah mereka merusak cout
objek? Saya memahami bahwa meskipun disinkronkan, Anda masih akan mendapatkan keluaran interleaved acak, tetapi apakah interleaving itu dijamin. Artinya, apakah aman digunakan cout
dari banyak utas?
Apakah vendor ini bergantung? Apa yang dilakukan gcc?
Penting : Harap berikan referensi untuk jawaban Anda jika Anda menjawab "ya" karena saya butuh semacam bukti untuk ini.
Perhatian saya juga bukan tentang panggilan sistem yang mendasarinya, itu baik-baik saja, tetapi aliran menambahkan lapisan buffer di atas.
printf
bersinar saat output lengkap ditulisstdout
dalam satu pengambilan; ketika menggunakanstd::cout
setiap tautan rantai ekspresi akan menjadi keluaran secara terpisahstdout
; di antara mereka mungkin ada beberapa utas lain yang menulisstdout
karena urutan hasil akhir menjadi kacau.Jawaban:
Standar C ++ 03 tidak mengatakan apa-apa tentang itu. Jika Anda tidak memiliki jaminan tentang keamanan thread dari sesuatu, Anda harus memperlakukannya sebagai tidak aman untuk thread.
Yang menarik di sini adalah fakta yang
cout
disangga. Sekalipun panggilan kewrite
(atau apa pun yang menyelesaikan efek itu dalam implementasi tertentu) dijamin eksklusif satu sama lain, buffer mungkin dibagikan oleh thread yang berbeda. Ini akan dengan cepat menyebabkan korupsi keadaan internal aliran.Dan bahkan jika akses ke buffer dijamin aman untuk thread, menurut Anda apa yang akan terjadi dalam kode ini?
Anda mungkin ingin setiap baris di sini bertindak dalam pengecualian timbal balik. Tapi bagaimana implementasi bisa menjamin itu?
Di C ++ 11, kami memiliki beberapa jaminan. FDIS mengatakan hal berikut di §27.4.1 [iostream.objects.overview]:
Jadi, Anda tidak akan mendapatkan aliran yang rusak, tetapi Anda masih perlu menyinkronkannya secara manual jika Anda tidak ingin keluarannya menjadi sampah.
sumber
cout.sync_with_stdio()
benar, menggunakancout
untuk mengeluarkan karakter dari beberapa utas tanpa sinkronisasi tambahan sudah ditentukan dengan baik, tetapi hanya pada tingkat byte individu. Jadi,cout << "ab";
dancout << "cd"
dieksekusi di utas yang berbeda dapat menghasilkanacdb
, misalnya, tetapi mungkin tidak menyebabkan Perilaku Tidak Terdefinisi.Ini pertanyaan yang bagus.
Pertama, C ++ 98 / C ++ 03 tidak memiliki konsep "utas". Jadi di dunia itu, pertanyaannya tidak ada artinya.
Bagaimana dengan C ++ 0x? Lihat jawaban Martinho (yang saya akui mengejutkan saya).
Bagaimana dengan implementasi spesifik sebelum C ++ 0x? Nah, sebagai contoh, berikut adalah kode sumber
basic_streambuf<...>:sputc
dari GCC 4.5.2 (header "streambuf"):Jelas, ini tidak melakukan penguncian. Dan juga tidak
xsputn
. Dan ini pasti jenis streambuf yang digunakan cout.Sejauh yang saya tahu, libstdc ++ tidak melakukan penguncian di sekitar operasi streaming mana pun. Dan saya tidak mengharapkan apapun, karena itu akan lambat.
Jadi dengan implementasi ini, jelas dimungkinkan untuk output dua utas saling korup ( tidak hanya menyisipkan).
Mungkinkah kode ini merusak struktur datanya sendiri? Jawabannya tergantung pada kemungkinan interaksi dari fungsi-fungsi ini; misalnya, apa yang terjadi jika satu thread mencoba membersihkan buffer sementara thread lain mencoba memanggil
xsputn
atau apa pun. Ini mungkin tergantung pada bagaimana kompilator dan CPU Anda memutuskan untuk menyusun ulang beban dan penyimpanan memori; dibutuhkan analisis yang cermat untuk memastikannya. Itu juga tergantung pada apa yang dilakukan CPU Anda jika dua utas mencoba mengubah lokasi yang sama secara bersamaan.Dengan kata lain, meskipun kebetulan berfungsi dengan baik di lingkungan Anda saat ini, ini mungkin rusak saat Anda memperbarui runtime, compiler, atau CPU Anda.
Ringkasan eksekutif: "Saya tidak akan". Buat kelas logging yang melakukan penguncian yang benar, atau pindah ke C ++ 0x.
Sebagai alternatif yang lemah, Anda dapat menyetel cout ke unbuffered. Kemungkinan (meskipun tidak dijamin) akan melewatkan semua logika yang terkait dengan buffer dan memanggil
write
secara langsung. Meskipun itu mungkin sangat lambat.sumber
cout
.www.techrepublic.com/article/use-stl-streams-for-easy-c-plus-plus-thread-safe-logging
dan juga: Apakah aliran keluaran standar dalam C ++ thread-safe (cout, cerr, clog)?
MEMPERBARUI
Silakan lihat jawaban @Martinho Fernandes untuk mengetahui tentang apa yang dikatakan standar baru C ++ 11 tentang ini.
sumber
Seperti jawaban lain yang disebutkan, ini pasti khusus vendor karena standar C ++ tidak menyebutkan threading (ini berubah dalam C ++ 0x).
GCC tidak menjanjikan banyak hal tentang keamanan thread dan I / O. Tetapi dokumentasi untuk apa yang dijanjikannya ada di sini:
hal utamanya mungkin:
Saya tidak tahu apakah ada yang berubah dari jangka waktu 3.0 yang disebutkan.
Dokumentasi keamanan untaian MSVC untuk
iostreams
dapat ditemukan di sini: http://msdn.microsoft.com/en-us/library/c9ceah3b.aspx :Perhatikan bahwa informasi tersebut adalah untuk versi MSVC terbaru (saat ini untuk VS 2010 / MSVC 10 /
cl.exe
16.x). Anda dapat memilih informasi untuk versi MSVC yang lebih lama menggunakan kontrol dropdown pada halaman (dan informasinya berbeda untuk versi yang lebih lama).sumber