Soru C ++: Rasgele işlev çağrısı için zaman aşımı nasıl uygulanır?


Maalesef belli bir süre içinde bazen bitmeyecek bir kütüphane fonksiyonunu çağırmam gerek. İşlevi çağırmanın bir yolu var, ancak içinde sona ermiyorsa iptal et n saniye?

Fonksiyonu değiştiremiyorum, bu yüzden iptal koşulunu doğrudan içine koyamıyorum. zorundayım harici olarak işleve bir zaman aşımı ekle.

Belki de belirli bir süre sonra sonlandırabilen bir (artırma) iş parçacığı olarak başlatmak olası bir çözüm olabilir mi? Böyle bir şey ister misiniz? Aslında işlevin olduğuna inanıyorum değil iş parçacığı güvenli, ama eğer bunu bir tek tek iplik, değil mi? Başka (daha iyi) çözümler var mı?


25
2018-05-18 21:20


Menşei


Kütüphane işlevi ne yapar? - peterchen
Uru, bir şey hesaplayın ... Belirli koşullar altında fiilen sona ermeyecek bilimsel bir hesaplama. - Frank


Cevaplar:


Bir yumurtlayabilirsin. boost::thread API’yı çağırmak için:

boost::thread api_caller(::api_function, arg1, arg2);
if (api_caller.timed_join(boost::posix_time::milliseconds(500)))
{
    // API call returned within 500ms
}
else
{
    // API call timed out
}

Boost, çalışan iş parçacığını öldürmenize izin vermez. Bu örnekte, sadece öksüz.

Bu API çağrısının ne yaptığına dikkat etmeniz gerekir, çünkü elde edilen kaynakları hiçbir zaman yayınlamayabilir.


18
2018-05-18 21:45



Api_function bir değer döndürürse, ona nasıl erişebilirim? - Rupert Jones
Bu yöntem, doğrudan API'yi çağıran basit bir functor oluşturur. Sonucu yakalamak için, API'nın dönüş kodunu başka bir yerden erişilebilen bir değişkene atamak için kendi functor'ınızı veya lambda'nızı yazmanız gerekir. C ++ 0x'da yazabilirsiniz RETTYPE retcode; boost::thread api_caller( [&retcode] (type1 arg1, type2 arg2) { retcode = ::api_function(arg1, arg2); }); - Ben Straub


Bunu başarmanın tek güvenli yolu, ayrı ayrı doğmak olurdu. kum havuzu kitaplık işlevini uygulamanıza bir proxy olarak çağıran işlem. Uygulamanız ve proxy arasında bir tür IPC uygulamanız gerekecek. IPC cevabını okumak için bir zaman aşımı uygulanması daha sonra oldukça önemsizdir. Zaman aşımı nedeniyle okuma başarısız olursa, uygulamanızın sağlığını riske atmadan proxy'yi güvenle sonlandırabilirsiniz.


15
2018-05-18 21:25





Bahsettiğiniz şey genellikle "watchdog" sistemi olarak adlandırılıyor. Watchdog tipik olarak, diğer tüm dişlerin durumunu kontrol eden ikinci bir ipliktir. Watchdog genellikle periyodik olarak çalışacak şekilde ayarlanmıştır. Diğer iş parçacıklarından herhangi bir yanıt alınmadıysa, bekçi kullanıcı kullanıcıyı bilgilendirebilir veya güvenli bir şekilde yapması durumunda rahatsız edici iş parçacığını öldürebilir (uygulamanıza göre değişir).


8
2018-05-18 21:23



Kütüphane işlevinin ne yaptığına bağlı olarak, yanıt vermeyen ipucunu öldürmek çok güvensiz olabilir. Güvenli bir yaklaşım, görevi ayrı bir sürece göndermek olacaktır. - An̲̳̳drew
Nasıl böyle bir süreç başlatırım? Uygulamam dosya sistemine geçmeden bazı verileri (ve sonuç verilerini geri al) iletebilir mi? - Frank
Bu biraz karmaşık ve platforma özgü - kolayca ayrı bir stackoverflow soru olabilir, bence. Veriler arasında veri aktarmanın çeşitli yolları vardır. Buna IPC (Inter-Process Communication) denir ve ayrıca platforma özgüdür. - An̲̳̳drew
Bu uygulama benim için yukarıdaki soruyu çözdü: comments.gmane.org/gmane.comp.lib.boost.user/59477 - Tom


Konuyla ilgili sorun, bazı kaynakların, iş parçacığı sonlandırıldıktan sonra ücretsiz olarak yararlanamayacağınızdır. Serbest bırakmanız gereken kaynakları elde edemiyorsanız, iş parçacığına gidin.


3
2018-05-18 21:25



Kontrolünüz altında olmayan kaynakların olabileceğini unutmayın - API'leri kilitleri ve benzerlerini arayabilir ve iş parçacığını sonlandırarak bu kilitleri yitirirsiniz. - Michael


Boost.Test'in execution_monitor istediğini yapar:

http://www.boost.org/doc/libs/1_39_0/libs/test/doc/html/execution-monitor/reference.html#boost.execution_monitor


3
2018-05-18 22:50



+1, ilginç bir fikir. Zaman aşımı parametresinin henüz Windows için çalışmadığını görüyorum. Ayrıca, işlev tarafından kullanılan herhangi bir kaynak hala belirsiz bir durumda (en azından ayrılmamış ve büyük olasılıkla geçersiz ara durumdaysa) bırakılacaktır, bu nedenle işlevinizi bir kereden fazla veya dokunulduğu herhangi bir şeye bağlı olarak çalıştırmayı denemeyin. - j_random_hacker
Bu sorunun güzel bir örneği var: Bu - asanguinetti


Sorun şu ki bir süreç içi çözümle işlevden destek almadan potansiyel olarak geçersiz durumla sonuçlanırsınız.

Örnek: Bir bellek ayırma gerçekleşirken iş parçacığını sonlandırdığınızda işlem yığınınız bozulmuş olabilir.

Böylece aramayı sonlandırabilirsin, ama sonra da süreci sonlandırmak zorundasın. Pek çok durumda, yıkıcı yan etkilerin şansı küçüktür, ancak bunun üzerine hesaplamam.

Ben Straub'un öne sürdüğü gibi, iş parçacığından öksüz kalacağım: onu en düşük önceliğe koy ve sonsuza dek koşmasına izin ver. Bu elbette ki sınırlı bir çözüm: eğer iplik kaynak tüketiyorsa (muhtemelen), sistemi yavaşlatırlar, ayrıca işlem başına ipliklerde bir sınırlama vardır (genellikle iplik yığını için adres alanı nedeniyle).

Genel olarak, harici işlem çözümünü tercih ederim. Basit bir desen şu:
Girdi verilerini bir dosyaya yaz, dış işlemi argüman olarak dosya ile başlat. Dış işlem, (varsa) izlenebilir bir disk dosyasına ilerleme kaydeder ve hatta işlemin başladığı yerden devam etmesine izin verebilir. Sonuçlar diske yazılır ve üst süreç bunları okuyabilir.

Süreci sona erdirdiğinizde, harici kaynaklara (dosyalar gibi) eşitleme erişimi ve terk edilmiş el işleri, yarı yazılı dosyalar vb. İle nasıl başa çıkılacağı konusunda hala anlaşmanız gerekir. Ancak bu genellikle sağlam bir çözümün yolu.


3
2018-05-20 08:13





İhtiyacın olan şey bir iş parçacığı ve bir Gelecek Nesne Bu, sonucu işlev çağrısından tutabilir.

Destek kullanarak bir örnek için bkz. İşte.

Zaman aşımından sonra geleceği kontrol etmeniz ve ayarlanmamışsa buna göre hareket etmelisiniz.


1
2018-05-18 21:59



Vadeler havalı ve genellikle faydalıdır, ancak OP'nin sorduğu problemi çözdüğünü sanmıyorum. O istiyor çalışan işlevi durdur eğer çok uzun sürerse. - j_random_hacker
Zaman aşımı süresi dolduğunda iş parçacığını sonlandırmaya çalışabilir, ancak diğerlerinin de işaret ettiği gibi güvenli değildir. Eğer işlev daha sonra sona eriyorsa (kırılmadıkça), o zaman gelecekteki zaman aşımından sonra ana programına devam etmesine izin verecek ve gelecekte bir süre sonra sona ereceğini bilerek ipliği ve geleceği görmezden gelecektir. - lothar


Yetim süreciyle devam edin, başlatın ve çalışmasını bekleyin. Zaman tükenirse, işletim sistemini öldürmek için onu çağır.

Irk kondisyonlarından nasıl kaçınılır. bu desende:

  • args depolamak için bir dosya oluşturmak (tabii ki, her şey VAL olarak geçirilir). Artık işlem sadece bu dosyadan veri okumasına izin verilir.

  • Öksüz, girdi verilerini işler, sonuç değerleriyle bir çıktı dosyası oluşturur ve kapatır.

  • Sadece her şey bittiğinde, yetim giriş dosyasını siler, bu, çalışmanın yapıldığı ana işlemi işaret eden bir gerçektir.

Bu, yarı yazılı dosyalar problemini okumayı engeller, çünkü ana önce girdi dosyasının yokluğunu fark eder, mutlaka tamamlanmış olan çıktı dosyasını okumak için açılır (çünkü girişi silmeden önce kapatılmış ve işletim sistemi yığınları sıralıdır).


1
2018-05-21 21:34





"Belirli bir süre içinde bazen sona ermeyecek bir kütüphane işlevini çağırmam gerekiyor, maalesef. Fonksiyonu çağırmanın bir yolu var mı ama n saniye içinde sona ermiyorsa iptal mi?"

Kısa cevap hayır. Bu genellikle sorun ... Aramanın kendisi bir süre sonra (kendi zaman aşımını uygulayarak) sona ermeli, ancak çağrıları engellemek genellikle sorun yaratır (ör. Gethostbyname ()) çünkü bu sizin (veya sistem) zaman aşımına bağlıdır, sizinki değil.

Bu nedenle, mümkün olduğunda, iplikte gerekli olan kodu temiz bir şekilde çıkarmaya çalışın - kodun kendisi, hatayı saptamalı ve ele almalıdır. Bir mesaj gönderebilir ve / veya durum belirleyebilir, böylece ana (veya başka bir iş parçacığı) ne olup bittiğini bilir.

Kişisel tercihler, yüksek derecede kullanılabilir sistemlerde, iş parçacıklarının sık sık dönmesini (belirli bir zaman aşımına uğramadan), özel zaman aşımları ile, engelleme işlevlerini çağırmayı ve kesin çıkış koşullarını yerine getirmeyi seviyorum. Global veya thread-spesifik 'done' değişkeni temiz bir çıkış için hile yapar.


1
2017-12-08 20:19