std :: shared_ptr iş parçacığı güvenliği açıklandı


106

Okuduğum http://gcc.gnu.org/onlinedocs/libstdc++/manual/shared_ptr.html ve bazı iş parçacığı güvenlik sorunları hala benim için açık değildir:

  1. Standart, referans sayımının iş parçacığı açısından güvenli olduğunu ve platformdan bağımsız olduğunu garanti eder, değil mi?
  2. Benzer sorun - standart, yalnızca bir iş parçacığının (son referansı tutan) paylaşılan nesnede silme çağrısı yapacağını garanti eder, değil mi?
  3. shared_ptr, içinde depolanan nesne için herhangi bir iş parçacığı güvenliğini garanti etmez mi?

DÜZENLE:

Sözde kod:

// Thread I
shared_ptr<A> a (new A (1));

// Thread II
shared_ptr<A> b (a);

// Thread III
shared_ptr<A> c (a);

// Thread IV
shared_ptr<A> d (a);

d.reset (new A (10));

İş parçacığı IV'teki reset () çağrısı, ilk iş parçacığında oluşturulan A sınıfının önceki örneğini silecek ve onu yeni örnekle değiştirecek mi? Ayrıca IV iş parçacığında reset () çağrıldıktan sonra diğer evreler sadece yeni oluşturulan nesneyi görecekler mi?


24
Doğru, doğru ve doğru.
spraff

16
make_sharedyerine kullanmalısınıznew
qdii

Yanıtlar:


87

Diğerlerinin de belirttiği gibi, orijinal 3 sorunuzu doğru bir şekilde çözdünüz.

Ama düzenlemenizin son kısmı

İş parçacığı IV'teki reset () çağrısı, ilk iş parçacığında oluşturulan A sınıfının önceki örneğini silecek ve onu yeni örnekle değiştirecek mi? Ayrıca IV iş parçacığında reset () çağrıldıktan sonra diğer evreler sadece yeni oluşturulan nesneyi görecekler mi?

yanlış. Sadece dyeni işaret eder A(10)ve a, bve corijinaline noktaya devam edecektir A(1). Bu, aşağıdaki kısa örnekte açıkça görülebilir.

#include <memory>
#include <iostream>
using namespace std;

struct A
{
  int a;
  A(int a) : a(a) {}
};

int main(int argc, char **argv)
{
  shared_ptr<A> a(new A(1));
  shared_ptr<A> b(a), c(a), d(a);

  cout << "a: " << a->a << "\tb: " << b->a
     << "\tc: " << c->a << "\td: " << d->a << endl;

  d.reset(new A(10));

  cout << "a: " << a->a << "\tb: " << b->a
     << "\tc: " << c->a << "\td: " << d->a << endl;
                                                                                                                 
  return 0;                                                                                                          
}

(Açıkçası, herhangi bir iş parçacığı ile uğraşmadım: bu, shared_ptr::reset()davranışı etkilemez .)

Bu kodun çıktısı

a: 1 b: 1 c: 1 d: 1

a: 1 b: 1 c: 1 d: 10


35
  1. Doğru, shared_ptrreferans sayma değerinin atomik artışlarını / azalmalarını kullanın.

  2. Standart, paylaşılan bir nesnede yalnızca bir iş parçacığının silme operatörünü çağıracağını garanti eder. Paylaşılan göstericinin kopyasını silen son iş parçacığının sil'i çağıran kişi olacağını özellikle belirtip belirtmediğinden emin değilim (muhtemelen pratikte durum böyle olacaktır).

  3. Hayır yok, içinde depolanan nesne aynı anda birden fazla iş parçacığı tarafından düzenlenebilir.

DÜZENLEME: Biraz takip, eğer paylaşılan işaretçilerin genel olarak nasıl çalıştığına dair bir fikir edinmek istiyorsanız, boost::shared_ptrkaynağa bakmak isteyebilirsiniz : http://www.boost.org/doc/libs/1_37_0/boost/shared_ptr.hpp .


3
1. "'Shared_ptrs' dediğinizde, bir referans sayım değerinin atomik artışlarını / düşüşlerini kullanın." Atomik artış / azalma için herhangi bir dahili kilit kullanmadıklarını mı kastediyorsunuz, hangisi bağlam değişir? Basit bir dilde, birden çok iş parçacığı kilidi kullanmadan referans sayısını artırabilir / azaltabilir mi? Atomik artış, özel atomic_test_and_swap / atomic_test_and_increment talimatları ile yapılır?
rahul.deshmukhpatil

@rahul derleyici bir muteks / kilit kullanmakta özgürdür, ancak çoğu iyi derleyici, kilitsiz yapılabilen platformlarda bir muteks / kilit kullanmayacaktır.
Bernard

@Bernard: platform için "derleyiciler std lib shared_ptr" uygulamasına bağlı mı demek istiyorsun?
rahul.deshmukhpatil

2
Evet. Anladığım kadarıyla standart, kilitsiz olması gerektiğini söylemiyor. Ancak en son GCC ve MSVC'de Intel x86 donanımında kilit yoktur ve diğer iyi derleyicilerin donanım desteklediğinde muhtemelen aynı şeyi yapacağını düşünüyorum.
Bernard

18

std::shared_ptr iş parçacığı güvenli değil.

Paylaşılan bir işaretçi, biri nesneye ve diğeri de kontrol bloğuna (ref sayacını tutan, zayıf işaretçilerle bağlantılar ...) olmak üzere iki işaretçi çiftidir.

Birden fazla std :: shared_ptr olabilir ve referans sayacını değiştirmek için kontrol bloğuna her eriştiklerinde iş parçacığı açısından güvenlidir, ancak std::shared_ptrkendisi iş parçacığı güvenli veya atomik değildir.

std::shared_ptrBaşka bir iş parçacığı onu kullanırken yeni bir nesne atarsanız , yeni nesne işaretçisi ile sonuçlanabilir ancak yine de eski nesnenin kontrol bloğuna bir işaretçi kullanır => CRASH.


4
Tek bir std::shared_ptrörneğin iş parçacığı açısından güvenli olmadığını söyleyebiliriz . Std :: shared_ptr referansı:If multiple threads of execution access the same shared_ptr without synchronization and any of those accesses uses a non-const member function of shared_ptr then a data race will occur;
JKovalsky

Bu daha iyi ifade edilebilir. Bir std::shared_ptr<T>örnek, iş parçacığı sınırları boyunca her zaman değer tarafından kullanıldığında (kopyalanır / taşınır) iş parçacığı açısından güvenli garantilidir . Diğer tüm kullanımlar, std::shared_ptr<T>&iş parçacığı sınırları boyunca güvensizdir
WhiZTiM
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.