C ++ 11 evre_yerel değişkenleri otomatik olarak statik midir?


85

Bu iki kod bölümü arasında bir fark var mı:

void f() {
    thread_local vector<int> V;
    V.clear();
    ... // use V as a temporary variable
}

ve

void f() {
    static thread_local vector<int> V;
    V.clear();
    ... // use V as a temporary variable
}

Arka plan: Başlangıçta bir STATİK vektör V (bazı ara değerleri tutmak için, işleve her girdiğimde temizlenir) ve tek iş parçacıklı bir programım vardı. Programı çok iş parçacıklı bir programa dönüştürmek istiyorum, bu yüzden bir şekilde bu statik değiştiriciden kurtulmam gerekiyor. Benim fikrim her durağanlığı thread_local'a dönüştürmek ve başka hiçbir şey için endişelenmemek? Bu yaklaşım geri tepebilir mi?


17
thread_localYerel bir değişkene sahip olmak , başlamak için mantıklı değil… her evrenin kendi çağrı yığını vardır.
Konrad Rudolph

1
Statik veya global değişkenlerin adresini döndürmek için orijinal olarak birkaç C işlevi yazılmıştır. Bunun daha sonra çok iş parçacıklı uygulamalarda (örn. Errno, localtime) kullanıldığında belirsiz hatalara yol açtığı bulundu. Ek olarak, bir işlev birden çok iş parçacığından çağrıldığında paylaşılan değişkenleri bir muteks ile korumak veya birçok çağrı nesnesi ve yöntemi arasında bir iş parçacığı bağlam nesnesi geçirmek zorunda kalmak bazen çok zararlıdır. Bir evre çözümüne yerel değişkenler bunlar ve diğer sorunlar.
edwinc

3
@Konrad Rudolph yerel değişkenleri her iş parçacığı için değişkenin bir örneğini başlatmak staticyerine yalnızca olarak bildiriyor static thread_local.
davide

1
@davide Ne benim ne de OP'nin amacı bu değil. Biz bahsetmiyoruz staticvs static thread_localziyade yaklaşık autovs thread_localöncesi C ++ 11 anlamını kullanılarak auto(yani otomatik depolama).
Konrad Rudolph

1
Ayrıca bkz. İş parçacığı yerel yerel statik değişkenler nasıl tanımlanır? . Hızlı bir dil avukat notu ... Microsoft ve TLS desteği Vista'da değişti; bkz İş Parçacığı Yerel Depolama (TLS) . Değişiklik, Singleton gibi şeyleri etkiler ve geçerli olabilir veya olmayabilir. Abondware yazılım modelini kullanıyorsanız, muhtemelen iyi olacaksınız. Birden çok derleyiciyi ve platformu desteklemekten memnunsanız, o zaman buna dikkat etmeniz gerekebilir.
jww

Yanıtlar:


94

C ++ Standardına göre

Evre_yerel bir blok kapsamı değişkenine uygulandığında, depolama sınıfı belirleyicisi statik ifade edilir açıkça görünmüyorsa edilir

Yani bu tanımın

void f() {
    thread_local vector<int> V;
    V.clear();
    ... // use V as a temporary variable
}

eşdeğerdir

void f() {
    static thread_local vector<int> V;
    V.clear();
    ... // use V as a temporary variable
}

Bununla birlikte, statik bir değişken, bir evre_yerel değişkeni ile aynı değildir .

1 thread_local anahtar sözcüğü ile bildirilen tüm değişkenler iş parçacığı saklama süresine sahiptir. Bu varlıklar için depolama, yaratıldıkları iş parçacığı süresince devam edecektir. Her iş parçacığı için ayrı bir nesne veya başvuru var ve bildirilen adın kullanımı mevcut evreyle ilişkili varlığa atıfta bulunuyor

Bu değişkenleri ayırt etmek için standart , statik depolama süresi ile birlikte yeni bir terim iş parçacığı depolama süresi sunar.


1
staticve externbu nedenle depolama sınıfını ima etmez, yalnızca iç kapsamlarda bile evre_yerel değişkenleri için bağlantı anlamına gelir.
Tekilleştirici

4
@Deduplicator Blok kapsam değişkenlerinin bağlantısı yoktur. Yani özgeçmişin yanlış. Yazıda yazdığım gibi iş parçacığı saklama süreleri var. Aslında statik depolama süresi ile aynıdır, ancak her iş parçacığına uygulanır.
Moskova'dan Vlad

1
Extern'i eklerseniz, bir tanım değil bir bildirim yaparsınız. Yani?
Tekilleştirici

1
@Deduplicator Yani bu, blok kapsam değişkenlerinin tanımlarının hiçbir bağlantısı olmadığı anlamına gelir.
Moskova'dan Vlad

1
Bunu VS 2013'te denedim ve "TL değişkenleri dinamik olarak başlatılamaz" diye bağırıyor. Şaşırdım.
v.oddou

19

Evet, "iş parçacığı yerel depolama" "genel" (veya "statik depolama") ile çok benzer, sadece "tüm programın süresi" yerine "tüm iş parçacığı süresi" var. Dolayısıyla, bir blok yerel evre-yerel değişkeni ilk kez denetim kendi bildiriminden geçer, ancak her evre içinde ayrı ayrı başlatılır ve evre bittiğinde yok edilir.


6

İle kullanıldığında thread_local,static blok kapsamında ima edilir (bkz. @ Vlad'ın cevabı), bir sınıf üyesi için talep edilir; Sanırım, ad alanı kapsamı için bağlantı anlamına geliyor.

9.2 / 6'ya göre:

Bir sınıf tanımı içinde, bir üye, statik olarak da belirtilmediği sürece, evre_yerel depolama sınıfı belirleyicisi ile bildirilmemelidir.

Orijinal soruyu cevaplamak için:

C ++ 11 evre_yerel değişkenleri otomatik olarak statik midir?

İsim-alanı değişkenleri dışında seçenek yoktur.

Bu iki kod bölümü arasında bir fark var mı:

Hayır.


4

İş parçacığı yerel depolaması statiktir ancak basit statik depolamadan oldukça farklı davranır.

Bir statik değişkeni bildirdiğinizde, değişkenin tam olarak bir örneği vardır. Derleyici / çalışma zamanı sistemi, tam olarak ne zaman belirtilmeden (bazı ayrıntılar burada atlanmıştır), onu gerçekten kullanmadan bir süre önce sizin için başlatılacağını garanti eder.

C ++ 11, bu başlatmanın iş parçacığı açısından güvenli olacağını garanti eder, ancak C ++ 11'den önce bu iş parçacığı güvenliği garanti edilmemiştir. Örneğin

static X * pointer = new X;

Birden fazla iş parçacığı aynı anda statik başlatma koduna ulaşırsa X'in örneklerini sızdırabilir.

Yerel bir değişken iş parçacığı bildirdiğinizde, değişkenin potansiyel olarak birçok örneği vardır. Onları thread-id tarafından indekslenmiş bir haritada olarak düşünebilirsiniz. Bu, her iş parçacığının değişkenin kendi kopyasını gördüğü anlamına gelir.

Bir kez daha, değişken başlatılırsa, derleyici / çalıştırma zamanı sistemi bu başlatmanın veriler kullanılmadan önce gerçekleşeceğini ve değişkeni kullanan her iş parçacığı için başlatmanın gerçekleşeceğini garanti eder. Derleyici ayrıca başlatmanın iş parçacığı açısından güvenli olacağını garanti eder.

İş parçacığı güvenliği garantileri, değişkenin beklediğiniz gibi davranmasını sağlamak için epeyce perde arkası kodu olabileceği anlamına gelir - özellikle derleyicinin önceden tam olarak kaç iş parçacığının olacağını bilmesinin bir yolu olmadığını düşünürsek programınızda var ve bunlardan kaç tanesi iş parçacığı yerel değişkenine dokunacak.


@Etherealone: ​​İlginç. Hangi özel bilgi? Bir referans verebilir misiniz?
Dale Wilson

1
stackoverflow.com/a/8102145/1576556 . Wikipedia C ++ 11 makalesi doğru hatırlıyorsam bundan bahsediyor.
Etherealone

1
Bununla birlikte, statik nesneler önce başlatılır, ardından kopyaya atanır. Bu nedenle, iş parçacığı güvenli başlatmanın tam ifadeyi içerip içermediğinden biraz emin değilim. Muhtemelen yapar çünkü aksi takdirde iş parçacığı için güvenli olarak kabul edilmeyecektir.
Etherealone
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.