Boost :: thread and boost :: mutex'i c ++ 11 eşdeğeriyle değiştirmek akıllı mı?


153

Motivasyon: Düşünme sebebim dehası proje müdürümün desteğin başka bir bağımlılık olduğunu ve korkunç olduğunu düşünüyor çünkü "buna güveniyorsun" (Desteğin kalitesini açıklamaya çalıştım, sonra bir süre sonra vazgeçtim :( Bunu yapmak istememin daha küçük bir nedeni, insanların içinde kod yazmaya başlayacağı için c ++ 11 özelliklerini öğrenmek istememdir.

  1. #include<thread> #include<mutex>Ve boost eşdeğerleri arasında 1: 1 eşleme var mı ?
  2. Boost şeylerini c ++ 11
    şeylerle değiştirmek için iyi bir fikir düşünür müsünüz? Kullanımım ilkel, ancak std ne destek sunmadığı zaman örnekler var mı? Yoksa (küfür) tam tersi?

PS Ben başlıkları orada GCC kullanın.


46
IMO Google kodlama yönergeleri pek çok açıdan aptalca ... Örneğin. C ++ 11'den otomatik izin
vermezler

5
Alıntı yönergeleri: [otomatik], okuyucular için yararlı olabilecek denetlenen artıklığı (tür adları gibi) okunabilirliği engeller [kaldırır].
Andrew Tomazos

31
için (otomatik it = v.begin () ... :)
NoSenseEtAl

15
@ AndrewTomazos-Fathomling: Gerçekten mi? Şahsen şimdiye kadar yineleyicinin gerçek türünü (belki birkaç kez) önemsediğimi sanmıyorum, sadece desteklenen işlemler ... Sözdizimsel artıklığın nadiren iyi bir düşünce (DRY) olduğunu iddia ediyorum.
Grizzly

16
btw google aptal yönergelerini değiştirdi, böylece sonunda otomatik olarak izin
verdiler

Yanıtlar:


192

Boost.Thread ve C ++ 11 standart iş parçacığı kitaplığı arasında birkaç fark vardır:

  • Boost iş parçacığı iptali destekler, C ++ 11 iş parçacıkları desteklemez
  • C ++ 11 destekler std::async, ancak Boost desteklemez
  • Boost, boost::shared_mutexçoklu okuyucu / tek yazarlı kilitleme için bir a sahiptir. Analog std::shared_timed_mutexsadece C ++ 14'ten ( N3891 ) std::shared_mutexberi kullanılabilirken, sadece C ++ 17'den ( N4508 ) beri mevcuttur .
  • C ++ 11 zaman aşımları Boost zaman aşımlarından farklıdır (ancak bu yakında Boost.Chrono kabul edilmiştir) değişecektir).
  • Bazı isimler farklı (ör. boost::unique_futureVs std::future)
  • Argümanı-geçen anlam std::threadfarklı olan boost::thread--- Kuvvetlendirme kullanımları boost::bindcopyable bağımsız değişken gerektirir. bağımsız değişken std::threadolarak yalnızca hareket türlerinin std::unique_ptrgeçirilmesine izin verir . Kullanımından dolayı , iç içe bağlama ifadeleri boost::bindgibi yer tutucuların anlambilimi _1de farklı olabilir.
  • Açıkça aramazsan join()veya detach()sonra boost::threadyıkıcı ve atama operatörü arayacak detach()atanmış / tahrip iplik nesne üzerinde. Bir C ++ 11 std::threadnesnesiyle bu std::terminate(), uygulamanın çağrılmasına ve uygulamanın iptal edilmesine neden olur.

Yalnızca taşıma parametreleriyle ilgili noktayı açıklığa kavuşturmak için aşağıdakiler geçerli C ++ 11'dir ve int, geçici öğenin sahipliğini yeni iş parçacığının başlatıldığı zamandaki std::unique_ptrparametreye aktarır f1. Ancak, boost::threadkullanırsanız boost::binddahili olarak kullandığı için çalışmaz ve std::unique_ptrkopyalanamaz. GCC ile birlikte sağlanan C ++ 11 iş parçacığı kitaplığında std::bind, buradaki uygulamada da kullanıldığı gibi, bu çalışmayı engelleyen bir hata vardır.

void f1(std::unique_ptr<int>);
std::thread t1(f1,std::unique_ptr<int>(new int(42)));

Boost kullanıyorsanız, derleyiciniz destekliyorsa muhtemelen nispeten ağrısız bir şekilde C ++ 11 iş parçacıklarına geçebilirsiniz (örn. Linux üzerindeki GCC'nin son sürümleri, -std=c++0xmodda mevcut olan C ++ 11 iş parçacığı kitaplığının çoğunlukla eksiksiz bir uygulamasına sahiptir ).

Derleyiciniz C ++ 11 iş parçacıklarını desteklemiyorsa, Just :: Thread gibi üçüncü taraf bir uygulama elde edebilirsiniz , ancak bu yine de bağımlılıktır.


1
Okuyucular ve yazarlar için ayrı kilitleme / kilit açma yöntemleri vardır ( yazarlar için lock/ unlockiçin / 'okuyucular için' lock_shared / unlock_shared '). Birden fazla okuyucu, yazar kullanmadıkça lock_shared'i engellemeden çağırabilir.
Dave S

2
shared_mutexDocs altındadır boost.org/doc/libs/1_47_0/doc/html/thread/... . Muteksi paylaşılan veya özel olarak kilitlersiniz ve sonra karşılık gelen kilit açma işlevini kullanırsınız. Bunu yapmak için RAII türlerini de kullanabilirsiniz ( shared_lockpaylaşılan bir okuma kilidi alır lock_guardve unique_locközel bir kilit alır). Ben sadece hareket türleri ile ilgili noktayı açıklığa kavuşturmaya çalıştım.
Anthony Williams

3
Beni harekete geçiren küçük bir şey daha var: Artırıldığında , çalışan bir iş parçacığının yıkıcısı onu ayırır ( boost.org/doc/libs/1_47_0/doc/html/thread/… ), C ++ ile çalışan bir iş parçacığının yıkıcısı sona erer () (FDIS 30.3.1.3)
Cubbi

3
C ++ 11'de try_scoped_lockişlevsellik kapsamındadır std::unique_lock. Bir muteksi alan std::try_to_lockve daha sonra try_lock()muteksi çağırmak için bir yapıcı var lock(). Bkz. Stdthread.co.uk/doc/headers/mutex/unique_lock/…
Anthony Williams

4
Evet, Boost.Thread, özellikle Vicente Botet'in çalışması nedeniyle yazdığımdan beri C ++ 11 standardına çok daha yakın hale geldi.
Anthony Williams

24

std::threadbüyük ölçüde örnek alındı boost::threadbirlikte, birkaç farklılık :

  • boost'un kopyalanamayan, bir tutamacı-bir-os-iş parçacığı, semantiği korunur. Ancak bu iplik, fabrika işlevlerinden iplik döndürülmesine ve kaplara yerleştirilmesine izin vermek için hareketlidir.
  • Bu teklif boost::thread, önemli bir komplikasyon olan iptal işlemini ekler . Bu değişikliğin yalnızca iş parçacığı üzerinde değil, C ++ iş parçacığı kitaplığının geri kalanı üzerinde de büyük etkisi vardır. Bu büyük değişimin fayda nedeniyle haklı olduğuna inanılmaktadır.
    • Ana iplik iptal edildiğinde çocuk ipliklerinin yanlışlıkla sızmasını önlemek için, iplik yıkıcı artık ayırmadan önce iptal çağrısı yapmalıdır.
    • İptal etmeden ayrılmayı etkinleştirmek için artık açık bir ayırma üyesi gereklidir.
  • İş parçacığı tanıtıcısı ve iş parçacığı kimliği kavramları iki sınıfa ayrılmıştır (bunlar aynı sınıftır boost::thread). Bu, iş parçacığı kimliğinin daha kolay değiştirilmesini ve depolanmasını desteklemek içindir.
  • Başka hiçbir birleştirilebilir iş parçacığına eşit karşılaştırılması garanti edilen bir iş parçacığı kimliği oluşturma yeteneği eklenmedi (buna boost::threadsahip değil). Bu, önceki çağrı ile aynı iş parçacığı tarafından yürütülüp yürütülmediğini bilmek isteyen kod için kullanışlıdır (özyinelemeli muteksler somut bir örnektir).
  • İstemciler isterse altta yatan işletim sistemini kullanarak iş parçacıklarını değiştirebilmeleri için yerel iş parçacığı tutamacını almak için bir "arka kapı" vardır.

Bu 2007'den beri, bazı noktalar artık geçerli değil: şimdi boost::threadbir native_handleişlevi var ve yorumcular belirttiği gibi std::threadartık iptal yok.

Ben ile önemli bir fark bulamadık boost::mutexve std::mutex.


2
std::threadiptali yok; öyle boost::thread!
Anthony Williams

@Anthony interrupt()boost :: thread için anlamadığınızdan emin misiniz ? Ayrıca, 2007'den bu yana değişen orijinal bir teklif olduğu anlaşılıyor.
Alex B

4
Evet, yükseltme işlemindeki iptal işlemine "kesinti" denir. Evet, bu eski bir teklif. C ++ 11 standardının en son kamu taslağı (iş parçacığı kütüphanesini içerir) open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
Anthony Williams

6

Göç etmemek için bir sebep var std::thread.

Statik bağlantı kullanıyorsanız, std::threadbu gcc hataları / özellikleri nedeniyle kullanılamaz hale gelir:

Yani, ararsanız std::thread::detachveya std::thread::joinistisna veya çökmeye yol açacaksa, boost::threadbu durumlarda tamam çalışır.


Bir hatanın UNCONFIRMED ve diğerinin GEÇERSİZ olduğunu görüyorum libpthread.a. Söylediklerinden kesinlikle emin misin?
einpoklum

1
@einpoklum, kullanarak çalıştırabilmeniz gerekir Wl,--whole-archive -lpthread -Wl,--no-whole-archive, bu cevaba bakınız örneğin stackoverflow.com/a/23504509/72178 . Ancak, bağlantı kurmak çok basit bir yol değildir libpthread.ave aynı zamanda kötü fikir olarak kabul edilir.
ks1322

4
Bu hataların şu anda 2016 olduğu için düzeltildiğini varsayabilir miyiz? Hatalar 2012 yılında gönderildi ve gcc 4.9.2'den itibaren resmi olarak C ++ 11'i desteklediğinden, resmi destekten önce C ++ 11'den şikayet edemeyiz.
Splash

6

Kurumsal Vaka

Orta ve çok çeşitli işletim sistemlerinde çalışması gereken bir işletme için yazılım yazıyorsanız ve sonuç olarak bu işletim sistemlerinde çeşitli derleyiciler ve derleyici sürümleri (özellikle nispeten eski olanlar) ile oluşturuluyorsa, önerim Şimdilik tamamen C ++ 11. Bu, kullanamayacağınız anlamına gelir std::threadve kullanmanızı tavsiye ederim boost::thread.

Temel / Teknik Başlangıç ​​Kutusu

Bir veya iki işletim sistemi için yazıyorsanız, yalnızca C ++ 11'i (ör. VS2015, GCC 5.3, Xcode 7) destekleyen modern bir derleyici ile derlemeniz gerektiğinden emin olabilirsiniz ve zaten destek kütüphanesine bağlı olarak, std::threadiyi bir seçenek olabilir.

Benim deneyimim

Kişisel olarak sertleştirilmiş, yoğun olarak kullanılan, son derece uyumlu, çok modern kütüphanelere karşı boost gibi kütüphaneleri kısmi olarak kullanıyorum. Bu özellikle diş çekme gibi karmaşık programlama konuları için geçerlidir. Ayrıca, boost::threadçok çeşitli ortamlar, derleyiciler, iş parçacığı modelleri vb.


1
@UmNyobe Yine de haklı. C ++ 11 iş parçacığının birçok uygulaması o kadar kırılmış ki, insanların bunu kullanmayı bile düşündüğüne şaşırdım.
StaceyGirl

3

Visual Studio 2013 ile, bana bazı sorunlara neden std::mutexolandan farklı davranıyor gibi görünüyor boost::mutex( bu soruya bakın ).


1

C ++ 17'de std :: shared_mutex ile ilgili olarak eklendi

Buradaki diğer cevaplar genel olarak farklılıklar hakkında çok iyi bir genel bakış sağlar. Ancak, std::shared_mutexbu destek çözme ile ilgili birkaç sorun var .

  1. Yükseltilebilir mutisler. Bunlar yok std::thread. Bir okuyucunun sizden önce başka yazarların girmesine izin vermeden bir yazara yükseltilmesine izin verir . Bunlar, okuma modundayken büyük bir hesaplamayı (örneğin, bir veri yapısını yeniden endekslemek) önceden işlemek, daha sonra yazma kilidini kısa bir süre basılı tutarak reindex'i uygulamak için yazmaya yükseltmek gibi şeyleri yapmanızı sağlar.

  2. Adil. A ile sürekli okuma etkinliğiniz varsa std::shared_mutex, yazarlarınız süresiz olarak kilitlenecektir. Çünkü başka bir okuyucu gelirse, onlara her zaman öncelik verilecektir. İle boost:shared_mutex, tüm iş parçacıklarına sonunda öncelik verilecektir. (1) Ne okuyucular ne de yazarlar açlıktan ölmeyecek.

Bunun tl; dr, kesinti süresi ve çok yüksek çekişme olmayan çok yüksek verimli bir sisteminiz std::shared_mutexvarsa, bunun üzerine manuel olarak bir öncelik sistemi oluşturmadan asla sizin için çalışmayacaktır. boost::shared_mutexkutunun dışında çalışır, ancak bazı durumlarda onunla uğraşmanız gerekebilir. std::shared_mutexDavranışının, onu kullanan çoğu kodda gerçekleşmeyi bekleyen gizli bir hata olduğunu iddia ediyorum .

(1) Kullandığı gerçek algoritma OS iş parçacığı zamanlayıcısına dayanır. Deneyimlerime göre, okumalar doygun olduğunda, Windows'ta OSX / Linux'tan daha uzun duraklamalar (yazma kilidi alırken) vardır.


0

Boost yerine std paylaşılan_ptr kullanmaya çalıştım ve aslında bu sınıfın gcc uygulamasında bir hata buldum. Uygulamam iki kez çağrılan yıkıcı nedeniyle çöküyordu (bu sınıf iş parçacığı için güvenli olmalı ve bu tür sorunlar üretmemelidir). Boost :: shared_ptr'e taşındıktan sonra tüm problemler ortadan kalktı. C ++ 11'in mevcut uygulamaları hala olgun değildir.

Boost ayrıca daha fazla özelliğe sahiptir. Örneğin std sürümündeki başlık, bir akışa serileştirici sağlamaz (yani cout << süresi). Boost, kendi vb. Eşdeğerlerini kullanan ancak std sürümleriyle işbirliği yapmayan birçok kütüphaneye sahiptir.

Özetle - boost kullanarak yazılmış bir uygulamanız varsa, kodunuzu C ++ 11 standardına geçmek için biraz çaba harcamak yerine tutmak daha güvenlidir.


4
shared_ptrYıkıcı evreli olması gerekmez, 's tanımsız davranış başka bir iş parçacığı onu yok ederken nesneye ulaşmak bir iş parçacığı olması. GCC'nin shared_ptr dosyasında bir hata bulduğunuzu düşünüyorsanız , lütfen bunu bildirin , aksi takdirde yanlış kullandığınız olasılık dengesinde.
Jonathan Wakely
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.