Bir "while (1);" C ++ 0x'de


153

Güncellenmiş, aşağıya bakın!

Duydum ve C ++ 0x derleyicinin aşağıdaki snippet için "Merhaba" yazdırmasına izin verdiğini okudum

#include <iostream>

int main() {
  while(1) 
    ;
  std::cout << "Hello" << std::endl;
}

Görünüşe göre iş parçacıkları ve optimizasyon yetenekleri ile ilgili bir şey var. Bana öyle geliyor ki, bu birçok insanı şaşırtabilir.

Birinin bunun neden izin vermesi gerektiğine dair iyi bir açıklaması var mı? Başvuru için, en son C ++ 0x taslağı6.5/5

For ifadesi için for-init-ifadesinin dışında bir döngü,

  • kütüphane G / Ç işlevlerine çağrı yapmaz ve
  • geçici nesnelere erişmez veya bunları değiştirmez ve
  • senkronizasyon işlemi (1.10) veya atomik işlem gerçekleştirmez (Madde 29)

uygulama tarafından feshedileceği varsayılabilir. [Not: Bu, sonlandırma kanıtlanamamış olsa bile, boş döngülerin kaldırılması gibi derleyici dönüşümlerine izin vermek için tasarlanmıştır. - son not]

Düzenle:

Bu anlayışlı makalede , Standartlar metni hakkında

Ne yazık ki, "tanımsız davranış" kelimeleri kullanılmıyor. Bununla birlikte, standart "derleyici P'yi kabul edebilir" dediğinde, P olmayan özelliğine sahip bir programın tanımsız semantik olduğu ima edilir.

Bu doğru mu ve derleyicinin yukarıdaki program için "Bye" yazmasına izin veriliyor mu?


Burada , yukarıda bağlantılı makaleyi yapan Guy tarafından başlatılan, C'ye benzer bir değişiklikle ilgili daha da anlaşılır bir konu var . Diğer yararlı gerçeklerin yanı sıra, C ++ 0x için de geçerli görünen bir çözüm sunuyorlar ( Güncelleme : Bu, n3225 ile artık çalışmaz - aşağıya bakın!)

endless:
  goto endless;

Bir derleyicinin bunu optimize etmesine izin verilmiyor, öyle görünüyor, çünkü bir döngü değil, bir sıçrama. Başka bir adam C ++ 0x ve C201X'te önerilen değişikliği özetliyor

Bir döngü yazarak, programcı iddiasında ya döngü görünür davranışı ile bir şey (gerçekleştirir I / O kere uçucu nesneleri veya yapar senkronizasyonu veya atom işlemleri) yapar, ya da en sonunda son bulan. Yan etkisi olmayan sonsuz bir döngü yazarak bu varsayımı ihlal edersem derleyiciye yalan söylüyorum ve programımın davranışı tanımsız. (Şanslıysam, derleyici beni bu konuda uyarabilir.) Dil, görünür davranış olmadan sonsuz bir döngü ifade etmenin bir yolunu (artık sağlamaz mı?) Sağlamaz.


3.1.2011'de n3225 ile güncelleme: Komite metni 1.10 / 24'e taşıdı ve

Uygulama, herhangi bir iş parçacığının sonunda aşağıdakilerden birini yapacağını varsayabilir:

  • sonlandırmak
  • kütüphane G / Ç işlevini arama,
  • geçici bir nesneye erişme veya bu nesneyi değiştirme veya
  • bir senkronizasyon işlemi veya bir atomik işlem gerçekleştirin.

gotoHüner olacak değil artık işe!


4
while(1) { MyMysteriousFunction(); }bu gizemli işlevin tanımını bilmeden bağımsız olarak derlenebilir olmalı, değil mi? Peki herhangi bir kütüphane G / Ç işlevine çağrı yapıp yapmadığını nasıl belirleyebiliriz? Başka bir deyişle: kesinlikle ilk merminin ifade edilebileceği fonksiyonlara çağrı yapmaz .
Daniel Earwicker

19
@Daniel: Eğer fonksiyonun tanımına erişebiliyorsa, birçok şeyi kanıtlayabilir. İşlemler arası optimizasyon diye bir şey var.
Potatoswatter

3
Şu anda, C ++ 03, değişime izin verilen bir derleyici olduğunu int x = 1; for(int i = 0; i < 10; ++i) do_something(&i); x++;içine for(int i = 0; i < 10; ++i) do_something(&i); int x = 2;? Ya da muhtemelen başka bir yolla, döngüden önce xbaşlatılırken 2. Bu söyleyebilir do_somethingdeğeri umursamayan xonun a tamamen güvenli optimizasyon yüzden, eğer do_something neden olmaz değerinin iEğer sonsuz döngüye sonunda böyle değiştirmek için.
Dennis Zickefoose

4
Yani bu main() { start_daemon_thread(); while(1) { sleep(1000); } }, arka plan iş parçacığında daemon'umu çalıştırmak yerine hemen çıkabileceği anlamına mı geliyor?
Gabe

2
"Bu anlayışlı makale" sadece belirli, açık bir davranış olmadığı için belirli bir davranışın Tanımsız Davranış olduğunu varsayar. Bu yanlış bir varsayım. Genel olarak, standart sınırlı sayıda davranış bıraktığında, bir uygulama bunlardan herhangi birini seçmelidir ( Belirtilmemiş davranış). Bunun deterministik olması gerekmez. Hiçbir şey yapma döngüsünün sonlanıp sonlanmayacağı tartışmalı bir mantıksal seçimdir; ya öyle ya da değil. Başka bir şey yapmaya izin verilmez.
MSalters

Yanıtlar:


33

Birinin bunun neden izin vermesi gerektiğine dair iyi bir açıklaması var mı?

Evet, Hans Boehm N1528'de bunun için bir gerekçe sunuyor : Neden sonsuz döngüler için tanımlanmamış davranış? , bu WG14 belgesi olmasına rağmen gerekçe C ++ için de geçerlidir ve belge hem WG14 hem de WG21 için geçerlidir:

N1509'un doğru bir şekilde işaret ettiği gibi, mevcut taslak esasen 6.8.5p6'da sonsuz döngülere tanımsız davranış verir. Bunu yapmak için önemli bir sorun kodun sonlandırılmayan bir döngüde hareket etmesine izin vermesidir. Örneğin, count ve count2 öğelerinin genel değişkenler olduğu (veya adreslerinin alınmış olduğu) ve p'nin adresleri alınmamış olan yerel bir değişken olduğu aşağıdaki döngülere sahip olduğumuzu varsayalım:

for (p = q; p != 0; p = p -> next) {
    ++count;
}
for (p = q; p != 0; p = p -> next) {
    ++count2;
}

Bu iki döngü birleştirilebilir ve aşağıdaki döngü ile değiştirilebilir mi?

for (p = q; p != 0; p = p -> next) {
        ++count;
        ++count2;
}

Sonsuz döngüler için 6.8.5p6'da özel dağıtım yapılmazsa, buna izin verilmez: İlk döngü sona ermezse, q dairesel bir listeye işaret ettiğinde, orijinal asla count2'ye yazmaz. Böylece count2'ye erişen veya güncelleyen başka bir evre ile paralel olarak çalıştırılabilir. Bu, sonsuz döngüye rağmen count2'ye erişen dönüştürülmüş sürümle artık güvenli değil. Böylece dönüşüm potansiyel olarak bir veri yarışı getirir.

Bu gibi durumlarda, bir derleyicinin döngü sonlandırmasını kanıtlaması pek olası değildir; q'nun ana akım derleyicilerin yeteneğinin ötesinde olduğuna ve tüm program bilgisi olmadan çoğu zaman imkansız olduğuna inandığım döngüsel bir listeye işaret ettiğini anlamak gerekir.

Sonlandırıcı olmayan döngülerin getirdiği kısıtlamalar, derleyicinin sonlamayı kanıtlayamadığı sonlandırma döngülerinin optimizasyonunun yanı sıra aslında sonlandırılmayan döngülerin optimizasyonuna da bir kısıtlamadır. Birincisi, ikincisinden çok daha yaygındır ve genellikle optimize etmek daha ilginçtir.

Ayrıca, bir derleyicinin sonlandırmayı kanıtlamasının zor olacağı bir tamsayı döngü değişkenine sahip döngüler de vardır ve bu nedenle derleyicinin 6.8.5p6 olmadan döngüleri yeniden yapılandırması zor olacaktır. Gibi bir şey bile

for (i = 1; i != 15; i += 2)

veya

for (i = 1; i <= 10; i += j)

ele alması önemsiz görünüyor. (İlk durumda, sonlandırmayı kanıtlamak için bazı temel sayı teorisi gereklidir, ikinci durumda, bunu yapmak için j'nin olası değerleri hakkında bir şeyler bilmemiz gerekir. İmzasız tamsayıların etrafını sarmak, bu muhakemenin bir kısmını daha da karmaşıklaştırabilir. )

Bu sorun, her ikisi de önem kazanması muhtemel olan ve sayısal kod için zaten önemli olan derleyici paralelleştirme ve önbellek optimizasyon dönüşümleri dahil olmak üzere hemen hemen tüm döngü yeniden yapılandırma dönüşümleri için geçerli gibi görünmektedir. Bu, özellikle çoğumuz nadiren kasıtlı olarak sonsuz döngüler yazdığından, sonsuz döngüleri mümkün olan en doğal şekilde yazabilme yararına önemli bir maliyete dönüşecek gibi görünmektedir.

C ile en büyük fark, C11'in C ++ 'dan farklı olan ve C11'de spesifik örneğinizi iyi tanımlanmış sabit ifadeler olan ifadeleri kontrol etmek için bir istisna sağlamasıdır .


1
Şimdiki dil tarafından kolaylaştırılan ve aynı zamanda "Bir döngünün sonlandırılması herhangi bir nesnenin durumuna bağlıysa, döngüyü yürütmek için gereken süre, gözlemlenebilir yan etki, böyle bir zaman sonsuz olsa bile ". Verilen do { x = slowFunctionWithNoSideEffects(x);} while(x != 23);döngüden sonra kaldırma kodu verilen xgüvenli ve makul görünebilir, ancak bir derleyicinin x==23böyle bir kodda varsaymasına izin vermek yararlı olmaktan daha tehlikeli görünür.
supercat

47

Bana göre, ilgili gerekçe:

Bu, sonlandırma kanıtlanamamış olsa bile, boş döngülerin çıkarılması gibi derleyici dönüşümlerine izin vermeyi amaçlamaktadır.

Muhtemelen bunun nedeni, sonlandırmanın mekanik olarak kanıtlanmasının zor olması ve sonlandırmanın kanıtlanamaması, aksi takdirde, bağımsız işlemlerin döngüden sonrasına veya sonrasına taşınması, bir iş parçacığında döngü sonrası işlemlerin gerçekleştirilmesi gibi yararlı dönüşümler yapabilen derleyicileri engellemesidir. döngü başka birinde yürütülür, vb. Bu dönüşümler olmadan, bir döngü bir ipliğin bahsedilen döngüyü bitirmesini beklerken diğer tüm evreleri engelleyebilir. (Ayrı VLIW komut akışları da dahil olmak üzere herhangi bir paralel işleme biçimi için "thread" i gevşek kullanıyorum.)

EDIT: Aptal örnek:

while (complicated_condition()) {
    x = complicated_but_externally_invisible_operation(x);
}
complex_io_operation();
cout << "Results:" << endl;
cout << x << endl;

Burada, bir iş parçacığının bunu yapmak daha hızlı complex_io_operationolurken, diğeri döngüdeki tüm karmaşık hesaplamaları yapıyor. Ancak alıntıladığınız madde olmadan, derleyici optimizasyonu yapabilmek için iki şeyi kanıtlamak zorundadır: 1) complex_io_operation()döngünün sonuçlarına bağlı değildir ve 2) döngünün sona ereceği . 1) ispatlamak oldukça kolaydır, kanıtlamak 2) durma problemidir. Madde ile, döngünün sona erdiğini varsayabilir ve paralellik kazanır.

Tasarımcıların, üretim kodunda sonsuz döngülerin meydana geldiği durumların çok nadir olduğunu ve genellikle bir şekilde G / Ç'ye erişen olay güdümlü döngüler gibi şeyler olduğunu düşündüm. Sonuç olarak, nadir görülen durumu (sonsuz döngüler) daha yaygın olan durumu (sonsuz olmayan, ancak mekanik olmayan, sonsuz olmayan döngüleri kanıtlamak) optimize etmek için kötümser hale getirdiler.

Bununla birlikte, öğrenme örneklerinde kullanılan sonsuz döngülerin sonuç olarak acı çekeceği ve başlangıç ​​kodunda gotcha'ları artıracağı anlamına gelir. Bunun tamamen iyi bir şey olduğunu söyleyemem.

DÜZENLEME: şimdi bağladığınız sezgisel makale ile ilgili olarak, "derleyici program hakkında X varsayabilir" mantıksal olarak "program X karşılamıyorsa, davranış tanımsız" eşdeğer olduğunu söyleyebilirim. Bunu şu şekilde gösterebiliriz: X özelliğini karşılamayan bir program olduğunu varsayalım. Bu programın davranışı nerede tanımlanır? Standart yalnızca X özelliğinin doğru olduğunu varsayarak davranışı tanımlar. Standart açıkça tanımsız davranışı beyan etmese de, ihmal ile tanımsız olduğunu beyan etmiştir.

Benzer bir argümanı düşünün: "derleyici, sıra değişkenleri arasında x değişkeninin en fazla bir kez atandığını varsayabilir", "sıra noktaları arasında birden çok kez atanmak tanımsızdır" ile eşdeğerdir.


"Kanıtlamak 1) oldukça kolaydır" - aslında derleyicinin Johannes'in sorduğu fıkra kapsamında döngü sonlandırmasına izin vermesi için 3 koşuldan hemen sonra gelmiyor mu? Bence, "döngü sonsuza dek eğirme dışında gözlemlenebilir bir etkisi yoktur" ve madde, "sonsuza kadar eğirme" gibi döngüler için garanti edilen davranış olmamasını sağlar.
Steve Jessop

@Steve: döngü sona ermezse kolaydır; ancak döngü sonlanırsa, işlenmesini etkileyen önemsiz davranışlar olabilir complex_io_operation.
Philip Potter

Hata! Evet, uçucu olmayan yerlileri / takma adları / G / Ç'de kullanılan her şeyi değiştirebileceğini kaçırdım. Yani haklısınız: mutlaka takip etmese de, derleyicilerin böyle bir modifikasyonun gerçekleşmediğini kanıtlayabileceği ve yaptığını kanıtlayan birçok durum var.
Steve Jessop

"Ancak bu, öğrenme örneklerinde kullanılan sonsuz döngülerin sonuç olarak acı çekeceği ve başlangıç ​​kodunda gotcha'ları artıracağı anlamına gelir. Bunun tamamen iyi bir şey olduğunu söyleyemem." Sadece optimizasyonlar kapalı derlemek ve hala çalışması gerekir
KitsuneYMG

1
@supercat: Açıkladığınız şey pratikte ne olacağı, ancak taslak standardın gerektirdiği şey değil. Derleyicinin bir döngünün sonlanıp sonlanmayacağını bilmediğini varsayamayız. Derleyici Eğer yapar sonlandırmak olmaz döngü biliyorum, onu istediği her şeyi yapabilir. DS9K olacak için burun şeytanlar yaratmak herhangi hiçbir I / O vb sonsuz döngüye (Bu nedenle, DS9K çözer durdurulması sorunu.)
Philip Potter

15

Düzenlemenizden doğru yorum olduğunu düşünüyorum: boş sonsuz döngüler tanımsız davranış.

Özellikle sezgisel bir davranış olduğunu söyleyemem, ancak bu yorum alternatif olandan daha mantıklıdır, derleyicinin keyfi olarak UB'yi çağırmadan sonsuz döngüleri görmezden gelmesine izin verilir .

Sonsuz döngüler UB ise, sadece sigara sonlandırma programları anlamlı kabul edilmez anlamına gelir: C ++ 0x göre onlar var hiçbir anlambilim.

Bu da belli bir anlam ifade ediyor. Bunlar, bir dizi yan etkinin artık meydana gelmediği (örneğin, hiçbir şey geri döndürülmeyen main) özel bir durumdur ve bir dizi derleyici optimizasyonu, sonsuz döngülerin korunmasıyla engellenir. Örneğin, döngünün hiçbir yan etkisi yoksa, hesaplamaları ilmek boyunca hareket ettirmek mükemmel bir şekilde geçerlidir, çünkü sonunda her durumda hesaplama gerçekleştirilecektir. Döngü asla sona ererse biz çünkü Ama biz, karşıya değil güvenle yeniden düzenlemek kod can olabilir sadece operasyonları aslında programı kilitleniyor önce idam hangi değişiyor. Bir asma programını UB olarak ele almazsak, yani.


7
“Boş sonsuz döngüler tanımsız davranış mıdır?” Alan Turing farklı olmaya yalvarırdı, ama sadece mezarında dönmeye başladığında.
Donal Fellows

11
@Donal: Bir Turing makinesindeki anlambilimi hakkında hiçbir şey söylemedim. C ++ 'da yan etkisi olmayan sonsuz bir döngünün anlambilimini tartışıyoruz . Ve okuduğumda, C ++ 0x bu tür döngülerin tanımsız olduğunu söylemeyi seçer.
jalf

Boş sonsuz döngüler aptalca olurdu ve onlar için özel kurallara sahip olmak için hiçbir sebep olmazdı. Kural, gelecekte ihtiyaç duyulacak olan ancak hemen değil bir şey hesaplayan sınırsız (umarım sonsuz değil) sürenin yararlı döngüleri ile başa çıkmak için tasarlanmıştır.
supercat

1
Bu, C ++ 0x'in gömülü aygıtlar için uygun olmadığı anlamına mı geliyor? Neredeyse tüm gömülü cihazlar sonlandırılmaz ve işlerini büyük bir yağ içinde yapar while(1){...}. Hatta rutin olarak while(1);bekçi köpeği destekli bir reset çağırmak için kullanıyorlar .
vsz

1
@vsz: ilk form iyi. Bir çeşit gözlemlenebilir davranışa sahip oldukları sürece sonsuz döngüler mükemmel bir şekilde tanımlanmıştır. İkinci form daha zordur, ancak iki kolay yolu düşünebilirim: (1) gömülü cihazları hedefleyen bir derleyici sadece bu durumda daha katı davranışları tanımlamayı seçebilir veya (2) bazı kukla kütüphane işlevini çağıran bir gövde oluşturabilirsiniz . Derleyici bu işlevin ne yaptığını bilmediği sürece, bazı yan etkilere sahip olabileceğini varsaymalıdır ve bu nedenle döngü ile uğraşamaz.
jalf

8

Bu başka bir iş parçacığına başvuran bu tür soru satırlarında olduğunu düşünüyorum . Optimizasyon bazen boş döngüleri kaldırabilir.


3
Güzel soru. Görünüşe göre o adam tam olarak bu paragrafın derleyicinin neden olmasına izin verdiği sorunu vardı. Cevaplardan biri ile bağlantılı tartışmada, "Maalesef," tanımsız davranış "kelimelerinin kullanılmadığı yazılmıştır . Ancak, standart her zaman 'derleyici P'yi kabul edebilir" der, "P" özelliği tanımlanmamış anlambilime sahip. " . Bu beni şaşırtıyor. Bu, yukarıdaki örnek programımın tanımlanmamış davranışa sahip olduğu ve hiçbir yerden çıkmayabileceği anlamına mı geliyor?
Johannes Schaub - litb

@Johannes: "varsayılabilir" metni, elimdeki taslakta başka hiçbir yerde oluşmaz ve "varsayabilir" sadece birkaç kez gerçekleşebilir. Bunu satır sonları arasında eşleşmeyen bir arama işlevi ile kontrol etsem de, bu yüzden bazılarını kaçırmış olabilirim. Bu yüzden yazarın genellemesinin kanıtlar konusunda garanti altına alındığından emin değilim ama bir matematikçi olarak argümanın mantığını kabul etmek zorundayım, derleyici yanlış bir şey varsa genel olarak bir şey çıkarabilir ...
Steve Jessop

... özellikle herhangi X için, derleyici izin verdiği programı kesinlikle Şüphesiz için derleyici izin programı X'e denk olduğunu anlamak için, UB çok güçlü bir şekilde ima hakkında derleyici'nın mantıkta bir çelişki izin anlamak olmasıdır bunu izin için yapmak o. Yazarla da aynı fikirdeyim, eğer UB amaçlanıyorsa açıkça belirtilmelidir ve eğer amaçlanmamışsa, spesifikasyon metni yanlıştır ve düzeltilmelidir (belki de spec-dil eşdeğeri ile "derlenebilir) etkisi olmayan kod ile döngü ", emin değilim).
Steve Jessop

@SteveJessop: Herhangi bir kod parçasının - sonsuz döngüler de dahil - yürütülmesinin, kod parçasının yaptığı bir şey gözlemlenebilir bir program davranışını etkileyeceği zamana kadar ertelenebileceğini söylemek ne düşünürdünüz? kural olarak, bir kod parçasının yürütülmesi için gereken süre - sonsuz olsa bile - "gözlemlenebilir bir yan etki" değildir. Bir derleyici, bir döngünün belirli bir değeri tutan bir değişken olmadan çıkamayacağını gösterebilirse, değişkenin bu değeri tuttuğu varsayılabilir, hatta döngünün bu değeri tutarak onunla çıkamayacağı da gösterilebilir.
Supercat

@supercat: Bu sonucu belirttiğiniz gibi, bunun bir şeyleri geliştirdiğini sanmıyorum. Döngü herhangi bir nesne Xve bit örüntüsü için muhtemelen hiçbir zaman çıkmazsa, xderleyici, ilmek Xkalıbı tutmadan çıkmadığını gösterebilir x. Bu tamamen doğru. Bu yüzden Xherhangi bir bit desenine sahip olduğu düşünülebilir ve bu yanlış için UB kadar kötü Xve xhızlı bir şekilde bazılarına neden olacaktır. Bu yüzden standartlarınızda daha hassas olmanız gerektiğine inanıyorum. Sonsuz bir döngünün sonunda "olanlardan" bahsetmek ve bunu bir sonlu işleme eşdeğer göstermek zordur.
Steve Jessop

8

İlgili sorun, derleyicinin yan etkileri çakışmayan kodu yeniden sıralamasına izin verilmesidir. Derleyici sonsuz döngü için sonlandırıcı olmayan makine kodu üretse bile şaşırtıcı yürütme sırası oluşabilir.

Bunun doğru yaklaşım olduğuna inanıyorum. Language spec, yürütme sırasını zorlamanın yollarını tanımlar. Yeniden sıralanamayan sonsuz bir döngü istiyorsanız, şunu yazın:

volatile int dummy_side_effect;

while (1) {
    dummy_side_effect = 0;
}

printf("Never prints.\n");

2
@ JohannesSchaub-litb: Bir döngü - sonsuz veya değil - yürütme sırasında herhangi bir değişken değişken okumaz veya yazmazsa ve bunu yapabilen herhangi bir işlevi çağırmazsa, bir derleyici döngünün herhangi bir bölümünü erteleyebilir orada hesaplanan bir şeye erişmek için ilk çaba. Verilen unsigned int dummy; while(1){dummy++;} fprintf(stderror,"Hey\r\n"); fprintf(stderror,"Result was %u\r\n",dummy);, birincisi fprintfidam edilebilirdi, ancak ikincisi yapamadı (derleyici hesaplamayı dummyikisi arasında hareket ettirebilir fprintf, ancak değerini yazdıranı geçemez).
Supercat

1

Sorunun belki de en iyi "Daha sonraki bir kod parçası önceki bir kod parçasına bağlı değilse ve önceki kod parçasının, sistemin başka herhangi bir parçası üzerinde herhangi bir yan etkisi yoksa, derleyicinin çıktısı eski kodun ne zaman tamamlanıp tamamlanmayacağına veya tamamlanıp tamamlanmadığına bakılmaksızın, birincisi döngüler içeriyor olsa bile , bir önceki kodun yürütülmesinden önce, sonra veya bunlarla karıştırılan sonraki kod parçasını yürütebilir .

geçersiz testfermat (int n)
{
  int a = 1, b = 1, c = 1;
  (pow (a, n) + pow (b, n)! = pow (c, n))
  {
    eğer (b> a) a ++; aksi takdirde (c> b) {a = 1; B ++}; başka {a = 1; b = 1; c ++};
  }
  printf ("Sonuç");
  printf ("% d /% d /% d", a, b, c);
}

gibi

geçersiz testfermat (int n)
{
  eğer (fork_is_first_thread ())
  {
    int a = 1, b = 1, c = 1;
    (pow (a, n) + pow (b, n)! = pow (c, n))
    {
      eğer (b> a) a ++; aksi takdirde (c> b) {a = 1; B ++}; başka {a = 1; b = 1; c ++};
    }
    signal_other_thread_and_die ();
  }
  else // İkinci konu
  {
    printf ("Sonuç");
    wait_for_other_thread ();
  }
  printf ("% d /% d /% d", a, b, c);
}

Genellikle mantıksız değil, ancak endişelenebilirim:

  int toplam = 0;
  (i = 0; num_reps> i; i ++)
  {
    update_progress_bar (i)
    Toplam + = do_something_slow_with_no_side_effects (i)
  }
  (Toplam) show_result;

olacaktı

  int toplam = 0;
  eğer (fork_is_first_thread ())
  {
    (i = 0; num_reps> i; i ++)
      Toplam + = do_something_slow_with_no_side_effects (i)
    signal_other_thread_and_die ();
  }
  Başka
  {
    (i = 0; num_reps> i; i ++)
      update_progress_bar (i)
    wait_for_other_thread ();
  }
  (Toplam) show_result;

Bir CPU'nun hesaplamaları, diğerinin ilerleme çubuğu güncellemelerini işlemesini sağlayarak, yeniden yazma verimliliği artıracaktır. Ne yazık ki, ilerleme çubuğu güncellemelerini olması gerekenden daha az kullanışlı hale getirecektir.


Bir ilerleme çubuğu görüntülemek bir kütüphane G / Ç çağrısı olduğundan ilerleme çubuğu durumunuzun ayrılamadığını düşünüyorum. Optimizasyonlar görünür davranışı bu şekilde değiştirmemelidir.
Philip Potter

@Philip Potter: Yavaş rutinin yan etkileri olsaydı, bu kesinlikle doğru olurdu. Önceki örneğimde, olmasaydı anlamsız olurdu, bu yüzden değiştirdim. Spesifikasyon hakkındaki yorumum, sistemin etkileri (yürütmek için gereken süre dışında) görünür hale gelinceye kadar yani show_result () çağrısı kadar yavaş kodun yürütülmesini ertelemesine izin verilmesidir. İlerleme çubuğu kodu çalışan toplamdan yararlanırsa veya en azından böyle yapıyorsa, bu yavaş kodla senkronize olmaya zorlar.
supercat

1
Bu, 0'dan 100'e kadar hızlı ilerleyen ve daha sonra yaşlar için asılı olan tüm ilerleme çubuklarını açıklar;)
paulm

0

Önemsiz durumlar için derleyicinin sonsuz bir döngü olması durumunda karar verilemez.

Farklı durumlarda, optimize edicinizin kodunuz için daha iyi bir karmaşıklık sınıfına ulaşması olabilir (örneğin, O (n ^ 2) ve optimizasyondan sonra O (n) veya O (1) alırsınız).

Bu nedenle, C ++ standardına sonsuz bir döngüyü kaldırmaya izin vermeyecek bir kural eklemek, birçok optimizasyonu imkansız hale getirecektir. Ve çoğu insan bunu istemiyor. Bence bu soruya oldukça cevap veriyor.


Başka bir şey: Hiçbir şey yapmayan sonsuz bir döngüye ihtiyacınız olan herhangi bir geçerli örnek görmedim.

Duyduğum bir örnek, aksi takdirde gerçekten çözülmesi gereken çirkin bir hackti: Sıfırlamayı tetiklemenin tek yolunun, saatin otomatik olarak yeniden başlatılması için cihazı dondurmak olduğu gömülü sistemler hakkındaydı.

Hiçbir şey yapmayan sonsuz döngüye ihtiyacınız olan geçerli / iyi bir örnek biliyorsanız, lütfen bana söyleyin.


1
Sonsuz bir döngü isteyebileceğiniz yere bir örnek: performans nedenleriyle uyumak istemediğiniz ve tüm kod bir veya iki kesintiyi askıya aldığı gömülü bir sistem?
JCx

@ Standart C'deki kesmeler ana döngünün kontrol ettiği bir bayrak ayarlamalıdır, bu nedenle bayrakların ayarlanması durumunda ana döngünün gözlemlenebilir davranışı olacaktır. Kesintilerde önemli kod çalıştırmak taşınabilir değildir.
MM

-1

Uçucu olmayan, senkronize olmayan değişkenler aracılığıyla diğer ipliklerle etkileşime girmeleri dışında artık yeni olabilecek döngülerin artık yeni bir derleyici ile yanlış davranış verebileceğini belirtmeye değer.

Başka bir deyişle, küresellerinizi uçucu hale getirin - ayrıca işaretçi / referans yoluyla böyle bir döngüye geçirilen argümanlar.


Diğer ipliklerle etkileşime giriyorsa, onları uçucu yapmamalı, atom haline getirmemeli veya bir kilitle korumamalısınız.
BCoates

1
Thjs korkunç bir tavsiye. Onları volatileyapmak ne gerekli ne de yeterlidir ve performansı dramatik bir şekilde incitir.
David Schwartz
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.