Derleyicim kullanılmayan statik thread_local sınıf üyemi yoksaydı mı?


10

Sınıfımda bazı iş parçacığı kaydı yapmak istiyorum, bu yüzden thread_localözelliği için bir kontrol eklemeye karar :

#include <iostream>
#include <thread>

class Foo {
 public:
  Foo() {
    std::cout << "Foo()" << std::endl;
  }
  ~Foo() {
    std::cout << "~Foo()" << std::endl;
  }
};

class Bar {
 public:
  Bar() {
    std::cout << "Bar()" << std::endl;
    //foo;
  }
  ~Bar() {
    std::cout << "~Bar()" << std::endl;
  }
 private:
  static thread_local Foo foo;
};

thread_local Foo Bar::foo;

void worker() {
  {
    std::cout << "enter block" << std::endl;
    Bar bar1;
    Bar bar2;
    std::cout << "exit block" << std::endl;
  }
}

int main() {
  std::thread t1(worker);
  std::thread t2(worker);
  t1.join();
  t2.join();
  std::cout << "thread died" << std::endl;
}

Kod basit. Benim Barsınıf statik sahiptir thread_localüyesi foo. Statik thread_local Foo foooluşturulursa, bir iş parçacığının oluşturulduğu anlamına gelir.

Ancak kodu çalıştırdığımda, Foo()baskılarda hiçbir şey yok ve yorumu Barkullanan yapıcıdaki yorumu kaldırırsam fookod iyi çalışıyor.

Bunu GCC (7.4.0) ve Clang (6.0.0) üzerinde denedim ve sonuçlar aynı. Derleyicinin fookullanılmayan ve bir örnek oluşturmadığını keşfettiğini tahmin ediyorum . Yani

  1. Derleyici static thread_localüyeyi görmezden geldi mi? Bunun için nasıl hata ayıklayabilirim?
  2. Öyleyse, normal bir staticüyenin neden bu sorunu yoktur?

Yanıtlar:


9

Gözleminizde bir sorun yok. [basic.stc.static] / 2 , statik depolama süresine sahip değişkenlerin ortadan kaldırılmasını yasaklar:

Statik depolama süresine sahip bir değişken başlatma veya yan etkilere sahip bir yıkıcıya sahipse, bir sınıf nesnesinin veya onun kopya / taşıma işleminin [class.copy] 'de belirtildiği gibi ortadan kaldırılabilmesi dışında kullanılmamış görünse bile ortadan kaldırılmayacaktır. .

Bu kısıtlama diğer depolama süreleri için mevcut değildir. Aslında, [basic.stc.thread] / 2 diyor ki:

İplik saklama süresi olan bir değişken ilk kullanımından önce başlatılır ve eğer inşa edilirse iplik çıkışında imha edilir.

Bu, odr kullanılmadığı sürece iş parçacığı saklama süresi olan bir değişkenin oluşturulması gerekmediğini gösterir.


Ama neden bu tutarsızlık?

Statik depolama süresi için, program başına değişkenin yalnızca bir örneği vardır. Yapımının yan etkileri önemli olabilir (biraz program çapında bir kurucu gibi), bu nedenle yan etkiler gereklidir.

Bununla birlikte, iş parçacığı yerel depolama süresi için bir sorun vardır: bir algoritma çok sayıda iş parçacığı başlatabilir. Bu ipliklerin çoğu için, değişken tamamen ilgisizdir. Harici bir fizik simülasyon kütüphanesi,std::reduce(std::execution::par_unseq, first, last) çok sayıda fooörnek oluşturması son derece , değil mi?

Tabii ki, odr kullanılmayan iplik yerel depolama süresi değişkenlerinin (örneğin bir iplik izleyici) yapılandırılmasının yan etkileri için meşru bir kullanım olabilir. Bununla birlikte, bunu garanti etme avantajı , yukarıda belirtilen dezavantajı telafi etmek için yeterli değildir, bu nedenle bu değişkenlerin tek kullanımlık olmadıkları sürece ortadan kaldırılmasına izin verilir. (Derleyiciniz yapmamayı tercih edebilir. Ve bununla std::threadilgilenen kendi paketleyicinizi de yapabilirsiniz .)


1
Tamam ... eğer standart böyle söylerse, öyle olsun ... Ama komitenin yan etkileri statik depolama süresi olarak görmesi garip değil mi?
ravenisadesk

@reavenisadesk Güncellenmiş cevaba bakın.
LF

1

Bu bilgiyi @LF'nin cevabını kanıtlayabilen " İş Parçacığı-Yerel Depolama için ELF Kullanımı " bölümünde buldum

Ayrıca, çalışma zamanı desteği, gerekli değilse yerel iş parçacığı deposunu oluşturmaktan kaçınmalıdır. Örneğin, yüklü bir modül, işlemi oluşturan birçok parçanın yalnızca bir iş parçacığı tarafından kullanılabilir. Tüm iş parçacıkları için depolama alanı ayırmak bellek ve zaman kaybı olacaktır. Tembel bir yöntem isteniyor. Dinamik olarak yüklenen nesneleri işleme gereksinimi, henüz tahsis edilmemiş depolama alanlarını tanımayı gerektirdiğinden, bu fazladan bir yük değildir. Bu, tüm iş parçacıklarını durdurmanın ve tüm iş parçacıkları için tekrar çalışmalarına izin vermeden önce depolama alanı ayırmanın tek alternatifidir.

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.