Bir işlemin C ++ 'da SIGABRT aldığı senaryolar nelerdir? Bu sinyal her zaman süreç içinden mi geliyor yoksa bu sinyal bir süreçten diğerine gönderilebilir mi?
Bu sinyali hangi işlemin gönderdiğini belirlemenin bir yolu var mı?
Bir işlemin C ++ 'da SIGABRT aldığı senaryolar nelerdir? Bu sinyal her zaman süreç içinden mi geliyor yoksa bu sinyal bir süreçten diğerine gönderilebilir mi?
Bu sinyali hangi işlemin gönderdiğini belirlemenin bir yolu var mı?
Yanıtlar:
abort()
çağıran sürece SIGABRT
sinyal gönderir, abort()
temelde bu şekilde çalışır.
abort()
genellikle dahili bir hatayı veya ciddi şekilde bozulmuş bir kısıtlamayı tespit eden kütüphane işlevleri tarafından çağrılır. Örneğin , iç yapıları yığın taşması nedeniyle hasar görürse malloc()
arayacaktır abort()
.
libc
aramaya çalışıyorum free()
olmayan bir başlatıldı / bozuk pointer üzerinde
Close()
yöntemi olmayan , bu yüzden unutuldu. Büyük kapsama alanı olsa vardı. : rolleyes:
SIGABRT
Ciddi hatalar durumunda libc ve diğer kütüphaneler tarafından programı iptal etmek için yaygın olarak kullanılır. Örneğin, glibc, SIGABRT
algılanan çift serbest veya diğer yığın bozulmaları durumunda bir gönderir .
Ayrıca, çoğu assert
uygulama SIGABRT
başarısız bir iddiada kullanılır.
Ayrıca, SIGABRT
diğer sinyaller gibi diğer işlemlerden de gönderilebilir. Elbette, gönderme işleminin aynı kullanıcı veya kök olarak çalışması gerekir.
kill(2)
Arayüzü kullanarak herhangi bir işleme herhangi bir sinyal gönderebilirsiniz :
kill -SIGABRT 30823
30823 dash
başlattığım bir süreçti, bu yüzden öldürmek istediğim süreci kolayca bulabildim.
$ /bin/dash
$ Aborted
Aborted
Çıkış nasıl görünüşte olan dash
bir SIGABRT bildirir.
Bu kullanarak herhangi sürecine doğrudan gönderilebilir kill(2)
ya da bir süreç aracılığıyla kendisine sinyali gönderebilir assert(3)
, abort(3)
ya da raise(3)
.
C ++ durumunda başka bir basit neden daha var.
std::thread::~thread{
if((joinable ())
std::terminate ();
}
yani iş parçacığının kapsamı sona erdi ancak aramayı da unuttunuz
thread::join();
veya
thread::detach();
GNU libc, /dev/tty
aramadan önce bazı ölümcül koşullarla ilgili bilgileri yazdırır abort()
(daha sonra tetiklenir SIGABRT
), ancak programınızı bir hizmet olarak çalıştırıyorsanız veya gerçek bir terminal penceresinde çalıştırmıyorsanız, bu mesaj kaybolabilir, çünkü tty mesajları görüntülemek için.
/ Dev / tty yerine stderr'e yazmak için libc'yi yeniden yönlendirmeyle ilgili yazımı görün:
/ Dev / tty'den yönlendirme yapan libc hata mesajlarını yakalama
Sürecin kendisinden SIGABRT aldığı bir durum: Hrvoje, kürtaj üreten ctordan çağrılan gömülü saf sanaldan bahsetti, bunun için bir örnek oluşturdum. Burada d inşa edildiğinde, önce temel A sınıfı ctorunu çağırır ve ibrenin içine kendi kendine geçer. a ctor, d henüz oluşturulmadığından tablo geçerli işaretçiyle doldurulmadan önce saf sanal yöntemi çağırır.
#include<iostream>
using namespace std;
class A {
public:
A(A *pa){pa->f();}
virtual void f()=0;
};
class D : public A {
public:
D():A(this){}
virtual void f() {cout<<"D::f\n";}
};
int main(){
D d;
A *pa = &d;
pa->f();
return 0;
}
derleme: g ++ -o aa aa.cpp
ulimit -c sınırsız
run: ./aa
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
Şimdi çekirdek dosyayı hızlıca görelim ve SIGABRT'nin gerçekten çağrıldığını doğrulayalım:
gdb aa core
bkz.
i r
rdx 0x6 6
rsi 0x69a 1690
rdi 0x69a 1690
rip 0x7feae3170c37
kodu kontrol et:
disas 0x7feae3170c37
mov $0xea,%eax = 234 <- this is the kill syscall, sends signal to process
syscall <-----
http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/
234 sys_tgkill pid_t tgid pid_t pid int sig = 6 = SIGABRT
:)
"@Sarnold" u belirtildiği gibi, herhangi bir süreç başka bir sürece sinyal gönderebilir, bu nedenle bir süreç SIGABORT'u diğer sürece gönderebilir ve bu durumda alma işlemi, kendi ayarlaması nedeniyle gelip gelmediğini ayırt edemez. bellek vb, ya da başkasının "tek noktaya", göndermek.
Çalıştığım sistemlerden birinde, işlemin kalp atışı vererek bazı görevlerden çıkıp çıkmadığını gerçekten tespit eden bir kilitlenme dedektörü var. Değilse, işlemin kilitlenme durumunda olduğunu bildirir ve SIGABORT'u ona gönderir.
Bu olası adayı, sorulan soruya referansla paylaşmak istedim.
Cevabımı rekabetçi bir programlama (cp) perspektifinden vereceğim , ancak diğer alanlar için de geçerlidir.
Birçok kez cp yaparken, kısıtlamalar oldukça büyük.
Örneğin : N, M, Q
Böyle değişkenlerle bir sorum vardı 1 ≤ N, M, Q < 10^5
.
Ben çıkıyordu hatam boyutu dizisi tamsayı bir 2D ilan oldu 10000 x 10000
içinde C++
ve mücadele SIGABRT
neredeyse 2 gün boyunca Codechef de hata.
Şimdi, eğer hesaplarsak:
Tipik bir tamsayı boyutu: 4 bayt
Dizimizdeki hücre sayısı: 10000 x 10000
Toplam boyut (bayt cinsinden): 400000000 bayt = 4 * 10 ^ 8 ≈ 400 MB
Bu tür sorulara yönelik çözümleriniz PC'nizde çalışacaktır (her zaman değil), bu boyutu karşılayabilir.
Ancak kodlama sitelerindeki kaynaklar (çevrimiçi hakimler) birkaç KB ile sınırlıdır.
Bu nedenle, SIGABRT
hata ve benzeri hatalar.
Sonuç:
Bu tür sorularda, bir dizi veya vektör veya bu boyutta başka bir DS bildirmemeliyiz, ancak görevimiz algoritmamızı onlarsız (DS) veya daha az bellekle çalışacak kadar verimli hale getirmektir.
Not : Bu hatanın başka nedenleri olabilir; yukarıda onlardan biriydi.