C ++ 11'de bir iş parçacığını nasıl sonlandırırım?


137

İş parçacığını doğru şekilde sonlandırmam veya bir "sonlandırma" komutuna yanıt vermem gerekmiyor. İş parçacığını saf C ++ 11 kullanarak zorla sonlandırmakla ilgileniyorum.


7
İşte bu konuyla ilgili güzel bir soru: stackoverflow.com/questions/2790346/c0x-thread-interruption "Tüm dil özellikleri, desteğin dile yerleşik olmadığını söylüyor"
Nemanja Boric

Yanıtlar:


139
  1. std::terminate()Herhangi bir iş parçacığından çağrı yapabilirsiniz ve bahsettiğiniz iş parçacığı zorla sona erecektir.

  2. ~thread()Hedef iş parçacığının nesnesi üzerinde, müdahale etmeden join()veya detach()bu nesne üzerinde çalıştırılmayı ayarlayabilirsiniz . Bu, 1. seçenek ile aynı etkiye sahip olacaktır.

  3. Bir istisna atan bir yıkıcıya sahip bir istisna tasarlayabilirsiniz. Ve sonra, hedef iş parçacığının, zorla sonlandırılması gerektiğinde bu istisnayı atmasını ayarlayın. Bunun zor kısmı, hedef iş parçacığının bu istisnayı atmasını sağlamaktır.

Seçenekler 1 ve 2, süreç içi kaynakları sızdırmaz, ancak her iş parçacığını sonlandırırlar .

Seçenek 3 muhtemelen kaynakları sızdıracaktır, ancak hedef iş parçacığının istisnayı atmayı kabul etmesi gerektiği için kısmen işbirlikçi.

C ++ 11'de (bildiğim kadarıyla) çok iş parçacıklı bir programda tek bir iş parçacığını işbirliği yapmadan öldürmenin (yani tüm iş parçacıklarını öldürmeden) taşınabilir bir yolu yoktur. Böyle bir özelliği tasarlamak için hiçbir motivasyon yoktu.

A std::threadşu üye işlevine sahip olabilir:

native_handle_type native_handle();

İstediğinizi yapmak için işletim sistemine bağlı bir işlevi çağırmak için bunu kullanabilirsiniz. Örneğin, Apple'ın işletim sistemlerinde bu işlev vardır ve native_handle_typebir pthread_t. Başarılı olursanız, kaynakları sızdırmanız olasıdır.


2
Üzerinde hafif nitpick "içi işlem kaynaklarını kaçak yok" : OS sürecini öldürdükten sonra tüm kaynaklarını geri edeceği ders doğru olmakla birlikte, kaynaklar vardır kadarıyla programı söz konusu olduğunda sızdırılmış. Bu genellikle alakasızdır, ancak yine de bazı durumlarda sorun olabilir. std::terminatene statik yıkıcıları çağırır ne de çıktı arabelleklerini temizler, bu nedenle kaynakların serbest bırakılma sırası iyi tanımlanmamıştır ve herhangi bir verinizin kullanıcı tarafından görülebilir veya kalıcı bir depoya yazılması konusunda herhangi bir garantiniz veya hatta tutarlı ve eksiksiz.
Damon

6
Ayrıca arayabilir exit()veya abort()aynı genel etkiye sahip olabilirsiniz.
n. zamirler 'm.

2
# 1 bir şaka ve @ChrisDodd haklı. Şaka, # 3'ün altındaki ilk cümlede verilen cevapta açıklanmıştır. Ayrıca Nanno Langstraat'ın cevabına ve altındaki yorumlara bakın.
Howard Hinnant

44

@Howard Hinnant cevabı doğru hem de ve kapsamlı. Ancak çok hızlı std::terminate()okunursa yanlış anlaşılabilir, çünkü (tüm süreç) @AlexanderVX'in aklındaki "sonlandırıcı" ile aynı adı taşıyor (1 iş parçacığı).

Özet: "1 iş parçacığını sonlandır + zorla (hedef iş parçacığı işbirliği yapmaz) + saf C ++ 11 = Olmaz."


15
Ahh, 1 numaram gerçekten komik. Hangi iş parçacığını zorla bitirmek istediğinizi belirtmeniz gerekmez. Sistem, hangisini zorla bitirmek istediğinizi sihirli bir şekilde bilir ve bunu yapar!
Howard Hinnant

9
Evet, std::terminate()cevap klasik bir yaramaz Djinn hikayesi gibidir; o şekilde muhtemelen rağmen, mektuba OP'ın isteği her şeyi değil karşılamaktadır geliyordu . Mütevazı mizah beni güldürdü. :-)
Nanno Langstraat

2
Masum C ++ acemilerinin çok fazla / çok uzun süre umutlanmalarını önlemelisiniz.
Nanno Langstraat

2
Zarif bir şekilde ifade edildi. :-)
Howard Hinnant

@NannoLangstraat lanet olsun ... Okuyana kadar çok büyük umutlarım vardı: (..lol, oh iyi + 1'ler her yerde
:)

13

Bu soru aslında daha derin bir yapıya sahiptir ve genel olarak çok iş parçacıklı kavramları iyi anlamak size bu konu hakkında fikir verecektir. Aslında, bunları kullanmamanız için uyarı vermeden eşzamansız aniden iş parçacığı sonlandırma olanakları sağlayan herhangi bir dil veya işletim sistemi yoktur. Ve tüm bu yürütme ortamları, geliştiriciye şiddetle tavsiye eder ve hatta işbirlikli veya eşzamanlı iş parçacığı sonlandırma temelinde çok iş parçacıklı uygulamalar oluşturmayı gerektirir. Bu ortak kararların ve tavsiyelerin nedeni, hepsinin aynı genel çok iş parçacıklı model temelinde inşa edilmesidir.

İkincisinin avantajlarını ve sınırlamalarını daha iyi anlamak için çoklu işlem ve çoklu okuma kavramlarını karşılaştıralım.

Çoklu işlem, tüm yürütme ortamının işletim sistemi tarafından kontrol edilen tamamen yalıtılmış süreçler kümesine bölündüğünü varsayar. Süreç, işlemin yerel belleği ve içindeki veriler ve dosyalar, soketler, senkronizasyon nesneleri gibi tüm sistem kaynakları dahil olmak üzere yürütme ortamı durumunu birleştirir ve izole eder. İzolasyon, sürecin kritik öneme sahip bir özelliğidir, çünkü hataların süreç sınırları tarafından yayılmasını sınırlar. Başka bir deyişle, hiçbir süreç sistemdeki başka bir sürecin tutarlılığını etkilemez. Aynısı işlem davranışı için de geçerlidir, ancak daha az kısıtlı ve daha bulanık bir şekilde. Böyle bir ortamda, herhangi bir süreç herhangi bir "keyfi" anda sonlandırılabilir, çünkü ilk olarak her işlem izole edilir, ikincisi,

Buna karşılık, çoklu okuma, aynı işlemde birden çok iş parçacığı çalıştırdığını varsayar. Ancak tüm bu iş parçacıkları aynı izolasyon kutusunu paylaşır ve sürecin dahili durumuna ilişkin herhangi bir işletim sistemi kontrolü yoktur. Sonuç olarak, herhangi bir iş parçacığı genel işlem durumunu değiştirebilir ve bozabilir. Aynı zamanda, iş parçacığının durumunun bir iş parçacığını tamamen öldürmek için güvenli olduğu iyi bilinen noktalar uygulama mantığına bağlıdır ve ne işletim sistemi ne de programlama dili çalışma zamanı için bilinmemektedir. Sonuç olarak, keyfi anda iş parçacığı sonlandırma, yürütme yolunun keyfi bir noktasında onu öldürmek anlamına gelir ve süreç genelinde veri bozulmasına, belleğe ve sızıntıya kolayca yol açabilir,

Bu nedenle ortak yaklaşım, geliştiricileri eşzamanlı veya işbirliğine dayalı iş parçacığı sonlandırmayı uygulamaya zorlamaktır; burada bir iş parçacığı başka bir iş parçacığı sonlandırmayı talep edebilir ve iyi tanımlanmış bir noktadaki diğer iş parçacığı bu isteği kontrol edebilir ve iyi tanımlanmış durumdan kapatma prosedürünü başlatabilir. tüm küresel sistem çapında kaynakların ve yerel süreç çapındaki kaynakların güvenli ve tutarlı bir şekilde serbest bırakılmasıyla.


8
Bu çok yardımcı bir cevap değil. Çoklu işleme burada alakalı değildir ve çoklu iş parçacığı ile ilgili gözlemler oldukça geniştir.
MSalters

4
Ayrıntılı olarak söylemek istediğim ve söylediğim şey, çok iş parçacıklı modelin zorunlu iş parçacığı sonlandırma için resmi bir yol sağlamadığıdır. C ++, bellek modeli, çok iş parçacıklı model vb. Dahil olmak üzere net modelleri takip etmek ister. Zorla iş parçacığı sonlandırma yöntemi, doğası gereği güvensizdir. C ++ standart komitesi onu C ++ 'ya eklemek zorunda kalırsa, bir sonraki "Method terminate () iş parçacığı yürütmeyi sonlandırır. Davranış tanımsız." İfadesi ile yapılır ve bu "biraz sihir yap ve (muhtemelen) iş parçacığı sonlandırır" gibi ses çıkarır. ".
Zerdüşt

C # bu özelliğe sahiptir.
Derf Skren

@Derf Skren "Aslında, bunları kullanmamanız için uyarı vermeden asenkron aniden iş parçacığı sonlandırma olanağı sağlayan herhangi bir dil veya işletim sistemi yoktur" (c) ZarathustrA "Açıklamalar: Önemli! Thread.Abort yöntemi dikkatli kullanılmalıdır . Özellikle, mevcut iş parçacığı dışındaki bir iş parçacığını iptal etmek için çağırdığınızda, hangi kodun yürütüldüğünü veya yürütülemediğini bilmiyorsunuz ... "(c) Microsoft bağlantısı: docs.microsoft.com/en-us/dotnet/ api /…
Zerdüşt

11

C ++ iş parçacığını sonlandırmak için işletim sistemine bağlı işlevi kullanmanın ipuçları:

  1. std::thread::native_handle()join()veya çağrılmadan önce yalnızca iş parçacığının geçerli yerel tutamaç türünü alabilir detach(). Bundan sonra native_handle()0 döndürür - pthread_cancel()coredump olacaktır.

  2. Yerel iş parçacığı sonlandırma işlevini etkin bir şekilde çağırmak için (örneğin pthread_cancel()), std::thread::join()veya std::thread::detach(). Böylece yerel sonlandırıcınız her zaman kullanılacak geçerli bir yerel tutamaç sahibi olur.

Daha fazla açıklama için lütfen bakınız: http://bo-yang.github.io/2017/11/19/cpp-kill-detached-thread .


6

Sanırım öldürülmesi gereken iş parçacığı ya herhangi bir bekleme modunda ya da ağır bir iş yapıyor. "Saf" bir yol kullanmanızı öneririm.

Bazı global boole tanımlayın:

std::atomic_bool stop_thread_1 = false;

Aşağıdaki kodu (veya benzerini), çağrı yığınındaki tüm işlevlerin evre doğal olarak sona erene kadar geri dönmesine neden olacak şekilde birkaç anahtar noktaya yerleştirin:

if (stop_thread_1)
    return;

Ardından iş parçacığını başka bir (ana) iş parçacığından durdurmak için:

stop_thread_1 = true;
thread1.join ();
stop_thread_1 = false; //(for next time. this can be when starting the thread instead)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.