Apa yang terjadi pada sebuah thread terpisah ketika main() keluar?

Asumsikan I'm mulai std::benang dan kemudian detach() itu, sehingga benang terus mengeksekusi meskipun std::benang yang pernah mewakili itu, berjalan keluar dari ruang lingkup.

Asumsikan lebih lanjut bahwa program ini tidak memiliki protokol yang reliable untuk bergabung dengan terpisah benang1, sehingga terpisah benang masih berjalan saat main() keluar.

Saya tidak dapat menemukan apa-apa dalam standar (lebih tepatnya, di N3797 C++14 raperda), yang menjelaskan apa yang harus terjadi, baik 1.10 atau 30.3 mengandung kata-kata yang bersangkutan.

1 yang Lain, mungkin setara, pertanyaannya adalah: "dapat terpisah thread yang pernah bergabung lagi", karena apapun protokol anda're inventing untuk bergabung, yang menandakan bagian yang harus dilakukan ketika benang itu masih berjalan, dan OS scheduler mungkin memutuskan untuk menempatkan benang untuk tidur selama satu jam setelah sinyal dilakukan dengan tidak ada cara untuk menerima akhir untuk andal mendeteksi bahwa benang benar-benar selesai.

Jika kehabisan main() terpisah dengan benang berjalan adalah perilaku tidak terdefinisi, maka any penggunaan std::benang::detach() adalah perilaku tidak terdefinisi kecuali thread utama tidak pernah keluar2.

Dengan demikian, berjalan keluar dari main() dengan terpisah thread yang berjalan harus memiliki defined efek. Pertanyaannya adalah: where (di C++ standard, tidak POSIX, bukan OS dokumen, ...) adalah efek-efek ditetapkan.

2 terpisah thread tidak dapat bergabung (dalam arti std::benang::join()). Anda can menunggu hasil dari terpisah benang (misalnya melalui masa depan dari std::packaged_task, atau dengan counting semaphore atau bendera dan kondisi variabel), tapi itu doesn't menjamin bahwa topik pesan telah selesai executing. Memang, kecuali anda menempatkan sinyal ke bagian destructor pertama otomatis objek dari benang, ada will, secara umum, sama kode (destruktor) yang menjalankan after signaling kode. Jika OS jadwal thread utama untuk mengkonsumsi hasil dan keluar sebelum melepaskan benang selesai menjalankan berkata destructors, apa yang akan^Wis didefinisikan terjadi?

Mengomentari pertanyaan (1)
Larutan

Jawaban untuk pertanyaan asli "apa yang terjadi pada sebuah thread terpisah saat main() keluar" adalah:

Hal ini terus berjalan (karena standar doesn't mengatakan itu dihentikan), dan yang's didefinisikan dengan baik, selama itu tidak menyentuh (otomatis|thread_local) variabel-variabel lain benang atau benda statis.

Hal ini tampaknya akan diizinkan untuk memungkinkan benang manajer sebagai objek statis (catatan di [dasar.mulai.istilah]/4 kata lebih banyak, terima kasih untuk @dyp untuk pointer).

Masalah timbul ketika penghancuran objek statis telah selesai, karena kemudian eksekusi memasuki rezim di mana hanya kode diperbolehkan dalam penanganan sinyal dapat mengeksekusi ([dasar.mulai.istilah]/1, 1 kalimat). C++ standar library, yang hanya <atom> library ([dukungan.runtime]/9, 2 kalimat). Khususnya, yang—secara umum—tidak termasuk condition_variable (it's pelaksanaannya ditetapkan apakah yang menyimpan untuk digunakan dalam sinyal handler, karena itu's bukan bagian dari <atom>).

Kecuali anda've dibatalkan stack pada titik ini, itu's sulit untuk melihat bagaimana untuk menghindari perilaku tidak terdefinisi.

Jawaban untuk kedua pertanyaan "dapat terlepas benang pernah bergabung lagi" adalah:

Ya, dengan *_at_thread_exit keluarga fungsi (notify_all_at_thread_exit(), std::janji::set_value_at_thread_exit(), ...).

Seperti yang tercantum dalam catatan kaki [2] dari pertanyaan, menandakan kondisi variabel atau semaphore atau atom counter tidak cukup untuk bergabung terpisah thread (dalam arti memastikan bahwa akhir eksekusi telah-terjadi-sebelum menerima kata signalling dengan menunggu thread), karena, pada umumnya, akan ada lebih banyak kode dieksekusi setelah misalnya notify_all() dari kondisi variabel, khususnya destruktor otomatis dan benang-objek lokal.

Menjalankan sinyal sebagai hal terakhir benang tidak (setelah destruktor otomatis dan benang-objek lokal telah-terjadi) adalah apa yang _at_thread_exit keluarga fungsi dirancang untuk.

Jadi, dalam rangka untuk menghindari perilaku tidak terdefinisi dalam tidak adanya pelaksanaan jaminan atas apa yang standar membutuhkan, anda perlu (manual) bergabung terpisah benang dengan _at_thread_exit fungsi melakukan signaling atau membuat thread terpisah mengeksekusi hanya kode yang akan aman untuk sinyal handler juga.

Komentar (7)

Memisahkan Benang

Menurut std::benang::melepaskan:

Memisahkan benang dari eksekusi dari thread objek, yang memungkinkan eksekusi untuk terus mandiri. Setiap sumber daya yang dialokasikan akan menjadi dibebaskan setelah benang keluar.

Dari pthread_detach:

pthread_detach() fungsi akan menunjukkan implementasi yang khusus untuk thread dapat direklamasi ketika itu thread berakhir. Jika benang tidak dihentikan, pthread_detach() tidak karena itu untuk mengakhiri. Efek dari beberapa pthread_detach() panggilan pada target yang sama thread yang tidak ditentukan.

Memisahkan benang ini terutama untuk menghemat sumber daya, dalam kasus aplikasi tidak perlu menunggu benang untuk menyelesaikan (misalnya daemon, yang harus dijalankan sampai proses terminasi):

  1. Untuk gratis aplikasi side handle: Satu dapat membiarkan std::benang objek keluar dari ruang lingkup tanpa bergabung, apa yang biasanya mengarah ke panggilan untuk std::menghentikan() pada kehancuran.
  2. Untuk memungkinkan OS untuk pembersihan benang sumber daya tertentu (TCB) secara otomatis segera setelah benang keluar, karena kita ditentukan secara eksplisit, bahwa kita tidak't tertarik bergabung dengan benang kemudian hari, dengan demikian, seseorang tidak bisa bergabung dengan yang sudah terlepas benang.

Membunuh Benang

Perilaku penghentian proses adalah sama sebagai salah satu thread utama, yang setidaknya bisa menangkap sinyal. Apakah atau tidak benang lain dapat menangani sinyal tidak begitu penting, sebagai salah satu bisa bergabung atau menghentikan thread lainnya di dalam thread utama's sinyal handler doa. (Terkait pertanyaan)

Seperti yang sudah disebutkan, thread apapun, baik terpisah atau tidak, akan mati dengan proses pada kebanyakan Os. Proses itu sendiri dapat dihentikan dengan menaikkan sinyal, dengan memanggil exit() atau kembali dari fungsi utama. Namun, C++11 tidak dapat dan tidak mencoba untuk menentukan secara tepat perilaku yang mendasari OS, sedangkan para pengembang Java VM pasti bisa abstrak perbedaan tersebut sampai batas tertentu. AFAIK, eksotis proses dan model threading yang biasanya ditemukan pada platform kuno (yang C++11 mungkin tidak't porting) dan berbagai sistem embedded, yang bisa memiliki khusus dan/atau terbatas bahasa implementasi perpustakaan dan juga terbatas dukungan bahasa.

Benang Dukungan

Jika benang tidak't didukung std::benang::get_id() harus mengembalikan invalid id (default dibangun std::benang::id) seperti yang ada's polos proses, yang tidak membutuhkan benang objek untuk menjalankan dan konstruktor std::benang harus membuang std::system_error. Ini adalah bagaimana saya memahami C++11 dalam hubungannya dengan hari ini's Os. Jika ada's OS dengan threading dukungan, yang doesn't menelurkan sebuah thread utama dalam proses, biarkan aku tahu.

Mengendalikan Benang

Jika salah satu kebutuhan untuk menjaga kontrol atas benang untuk shutdown yang tepat, seseorang dapat melakukannya dengan menggunakan sync primitif dan/atau semacam bendera. Namun, Dalam kasus ini, pengaturan shutdown bendera diikuti dengan bergabung adalah cara saya sukai, karena ada's tidak ada titik dalam meningkatkan kompleksitas dengan memisahkan benang, sebagai sumber daya yang akan dibebaskan pada waktu yang sama pula, di mana beberapa byte dari std::benang obyek vs kompleksitas yang lebih tinggi dan mungkin lebih sync primitif harus diterima.

Komentar (2)

Nasib benang setelah keluar program yang tidak terdefinisi perilaku. Tapi sistem operasi modern akan membersihkan semua thread yang dibuat oleh proses penutupan itu.

Ketika memisahkan sebuah std::benang, tiga kondisi ini akan terus mengadakan:

  1. *ini tidak lagi memiliki benang pun
  2. joinable() akan selalu sama dengan palsu
  3. get_id() sama std::benang::id()
Komentar (4)

Perhatikan kode berikut:


#include 
#include 
#include 
#include 

void thread_fn() {
  std::this_thread::sleep_for (std::chrono::seconds(1)); 
  std::cout 
Komentar (1)

Ketika thread utama (yaitu, benang yang menjalankan fungsi main ()) berakhir, maka proses dihentikan dan semua thread lain berhenti.

Referensi: https://stackoverflow.com/a/4667273/2194843

Komentar (0)

Untuk memungkinkan thread lain untuk melanjutkan eksekusi, thread utama harus mengakhiri dengan memanggil pthread_exit() daripada keluar(3). It's baik-baik saja untuk menggunakan pthread_exit di utama. Ketika pthread_exit digunakan, thread utama akan berhenti mengeksekusi dan akan tetap di zombie(mati) status sampai semua benang lain yang keluar. Jika anda menggunakan pthread_exit di thread utama, tidak bisa mendapatkan kembali status dari benang lain dan tidak bisa melakukan clean-up untuk thread lain (bisa dilakukan dengan menggunakan pthread_join(3)). Juga, it's baik untuk melepaskan benang(pthread_detach(3)) sehingga benang daya secara otomatis dirilis pada thread penghentian. Sumber daya yang dibagi tidak akan dibebaskan sampai semua benang yang keluar.

Komentar (2)