Pertanyaan std :: string dalam program multi-berulir


Mengingat bahwa:

1) Standar C ++ 03 tidak membahas keberadaan benang dengan cara apa pun

2) Standar C ++ 03 menyerahkannya pada implementasi untuk memutuskan apakah std::string harus menggunakan semantik Copy-on-Write dalam copy-konstruktornya

3) semantik Copy-on-Write sering menyebabkan perilaku tak terduga dalam program multi-threaded

Saya sampai pada kesimpulan berikut, yang tampaknya kontroversial,:

Anda tidak dapat menggunakan std :: string dalam program multi-threaded secara aman dan mudah

Jelas, tidak ada struktur data STL yang aman-thread. Tapi setidaknya, dengan std :: vector misalnya, Anda cukup menggunakan mutex untuk melindungi akses ke vektor. Dengan penerapan std :: string yang menggunakan SAP, Anda bahkan tidak dapat melakukan itu tanpa mengedit semantik penghitungan referensi jauh di dalam implementasi vendor.

Contoh dunia nyata:

Di perusahaan saya, kami memiliki aplikasi multi-threaded yang telah benar-benar diuji dan dijalankan melalui Valgrind berkali-kali. Aplikasi ini berjalan selama berbulan-bulan tanpa masalah apa pun. Suatu hari, saya mengkompilasi ulang aplikasi pada gcc versi lain, dan tiba-tiba saya mendapatkan segfault acak sepanjang waktu. Valgrind sekarang melaporkan akses memori tidak sah jauh di dalam libstdc ++, dalam konstruktor std :: string copy.

Jadi apa solusinya? Yah, tentu saja, saya bisa mengetik std::vector<char> sebagai kelas string - tapi sungguh, itu menyebalkan. Saya juga bisa menunggu C ++ 0x, yang saya doakan akan membutuhkan pelaksana untuk membatalkan COW. Atau, (bergidik), saya bisa menggunakan kelas string khusus. Saya pribadi selalu rel terhadap pengembang yang mengimplementasikan kelas mereka sendiri ketika perpustakaan yang sudah ada sebelumnya akan baik-baik saja, tapi jujur, saya perlu kelas string yang saya dapat yakin tidak menggunakan semantik COW; dan std :: string tidak menjamin itu.

Apakah saya benar itu std::string tidak bisa digunakan dengan andal sama sekali dalam program multi-threaded portabel? Dan apa solusi yang baik?


32
2017-11-02 12:55


asal


Jawaban:


Mengingat bahwa standar tidak mengatakan sepatah kata pun tentang model memori dan benar-benar tidak menyadari thread, saya akan mengatakan Anda tidak dapat benar-benar menganggap setiap implementasi akan non-sapi sehingga tidak, Anda tidak bisa

Terlepas dari itu, jika Anda tahu alat Anda, sebagian besar implementasi akan menggunakan string non-sapi untuk memungkinkan multi-threading.


4
2017-11-02 13:05



Anda tidak dapat melakukan apa pun dengan aman dan mudah dalam program multi-berulir. Tidak ada yang namanya program C ++ multi-threaded portabel, tepatnya karena thread melempar segalanya C ++ mengatakan tentang urutan operasi, dan hasil memodifikasi variabel apa pun, keluar dari jendela.

Juga tidak ada standar untuk menjamin hal itu vector dapat digunakan dengan cara Anda katakan. Akan sah untuk menyediakan implementasi C ++ dengan ekstensi threading di mana, katakanlah, setiap penggunaan vektor di luar rangkaian yang diinisialisasi menghasilkan perilaku tidak terdefinisi. Saat Anda memulai utas kedua, Anda tidak menggunakan C ++ standar lagi, dan Anda harus melihat ke vendor compiler Anda untuk apa yang aman dan mana yang tidak.

Jika vendor Anda menyediakan ekstensi threading, dan juga menyediakan std :: string dengan COW yang (karena itu) tidak dapat dibuat aman-thread, maka saya pikir untuk sementara argumen Anda adalah dengan vendor Anda, atau dengan ekstensi threading, tidak dengan standar C ++. Sebagai contoh, boleh dibilang POSIX seharusnya melarang string COW dalam program yang menggunakan pthreads.

Anda mungkin bisa membuatnya aman dengan memiliki mutex tunggal, yang Anda ambil saat melakukan mutasi string apa pun, dan setiap bacaan string yang merupakan hasil dari salinan. Tapi Anda mungkin akan mendapatkan pertikaian yang melumpuhkan pada mutex itu.


11
2017-11-02 13:11



Kamu benar. Ini akan diperbaiki dalam C ++ 0x. Untuk saat ini Anda harus bergantung pada dokumentasi implementasi Anda. Misalnya, libstdc ++ Versi terbaru (GCC) memungkinkan Anda menggunakan objek string seolah-olah tidak ada objek string yang membagi buffernya dengan yang lain. C ++ 0x memaksa implemetasi perpustakaan untuk melindungi pengguna dari "berbagi tersembunyi".


8
2017-12-23 12:16



Cara yang lebih tepat untuk melihatnya adalah "Anda tidak dapat menggunakan C ++ dalam lingkungan multithread dengan aman dan mudah". Tidak ada jaminan bahwa struktur data lain akan berperilaku baik. Atau bahwa runtime tidak akan meledakkan komputer Anda. Standar tidak menjamin apa pun tentang utas.

Jadi yang harus dilakukan apa pun dengan utas pada C ++, Anda harus bergantung pada jaminan yang ditentukan oleh implementasi. Dan kemudian Anda dapat menggunakan dengan aman std::string karena setiap penerapan memberi tahu Anda apakah aman untuk digunakan dalam lingkungan berulir atau tidak.

Anda kehilangan semua harapan akan portabilitas sejati saat Anda menelurkan utas kedua. std::string bukan "kurang portabel" dari sisa bahasa / perpustakaan.


4
2017-12-21 14:32



Anda dapat menggunakan STLport. Ini menyediakan string non-COW. Dan itu memiliki perilaku yang sama pada platform yang berbeda.

Ini artikel menyajikan perbandingan string STL dengan copy-on-write dan noncopy- on-write argorithms, berdasarkan string STLport, tali dan GNU libstdc ++ implementasi.

Di perusahaan tempat saya bekerja, saya memiliki pengalaman menjalankan aplikasi server yang sama dengan STLport dan tanpa STLport di HP-UX 11.31. Aplikasi dikompilasi dengan gcc 4.3.1 dengan tingkat optimasi O2. Jadi ketika saya menjalankan progrma yang dibangun dengan STLport, prosesnya meminta 25% lebih cepat dibandingkan dengan program yang sama yang dibangun tanpa STLport (yang menggunakan perpustakaan STL sendiri).

Saya membuat kedua versi dan menemukan bahwa versi tanpa STLport menghabiskan lebih banyak waktu pthread_mutex_unlock() (2,5%) dibandingkan dengan versi dengan STLport (1%). Dan pthread_mutex_unlock() sendiri dalam versi tanpa STLport dipanggil dari salah satu fungsi std :: string.

Namun, ketika setelah membuat profil, saya mengubah tugas ke string di paling sering disebut fungsi dengan cara ini:

string_var = string_var.c_str(); // added .c_str()

ada peningkatan signifikan dalam kinerja versi tanpa STLport.


2
2017-11-02 13:04



Saya mengatur akses string:

  • membuat std::string anggota pribadi
  • kembali const std::string& untuk getter
  • setter memodifikasi anggota

Ini selalu bekerja dengan baik untuk saya dan menyembunyikan data yang benar.


0
2017-12-21 14:35



Di MSVC, std :: string tidak lagi referensi pointer bersama yang dihitung ke penampung. Mereka memilih seluruh konten dengan nilai di setiap konstruktor copy dan operator penugasan, untuk menghindari masalah multithreading.


0
2017-11-02 17:18