Dalam urutan apa saya harus mengirim sinyal ke proses shutdown yang anggun?

90

Dalam sebuah komentar atas jawaban dari pertanyaan lain ini , pemberi komentar berkata:

jangan gunakan kill -9 kecuali benar-benar diperlukan! SIGKILL tidak dapat dijebak sehingga program yang dimatikan tidak dapat menjalankan rutinitas shutdown apa pun untuk misalnya menghapus file-file sementara. Pertama coba HUP (1), lalu INT (2), lalu QUIT (3)

Saya setuju pada prinsipnya tentang SIGKILL, tetapi sisanya adalah berita bagi saya. Mengingat bahwa sinyal default yang dikirim oleh killadalah SIGTERM, saya berharap itu adalah sinyal yang paling umum diharapkan untuk mematikan proses arbitrer dengan baik. Juga, saya telah melihat SIGHUPdigunakan untuk alasan non-terminating, seperti memberitahu daemon "baca ulang file konfigurasi Anda." Dan menurut saya SIGINT(interupsi yang sama yang biasanya Anda dapatkan dengan Ctrl-C, kan?) Tidak didukung secara luas sebagaimana mestinya, atau berakhir dengan agak tidak wajar.

Mengingat itu SIGKILLadalah pilihan terakhir - Sinyal mana, dan dalam urutan apa , yang harus Anda kirimkan ke proses sewenang-wenang, untuk menghentikannya seanggun mungkin?

Harap dukung jawaban Anda dengan fakta pendukung (di luar preferensi atau opini pribadi) atau referensi, jika Anda bisa.

Catatan: Saya sangat tertarik dengan praktik terbaik yang mencakup pertimbangan bash / Cygwin.

Edit: Sejauh ini, sepertinya tidak ada yang menyebut INT atau QUIT, dan HUP juga terbatas. Apakah ada alasan untuk memasukkan ini ke dalam proses pembunuhan yang teratur?

sistem JEDA
sumber
4
Jika Anda harus menggunakan SIGKILL untuk benar-benar mematikan suatu proses, saya akan menganggapnya sebagai bug dalam program.
sigjuice

Jawaban:

121

SIGTERM memberi tahu aplikasi untuk dihentikan. Sinyal lain memberi tahu aplikasi hal-hal lain yang tidak terkait dengan penghentian tetapi terkadang memiliki hasil yang sama. Jangan gunakan itu. Jika Anda ingin aplikasi ditutup, beri tahu. Jangan berikan sinyal yang menyesatkan.

Beberapa orang percaya bahwa cara standar cerdas untuk menghentikan suatu proses adalah dengan mengirimkannya banyak sinyal, seperti HUP, INT, TERM, dan akhirnya KILL. Ini konyol. Sinyal yang tepat untuk penghentian adalah SIGTERM dan jika SIGTERM tidak menghentikan proses secara instan, seperti yang Anda inginkan, itu karena aplikasi telah memilih untuk menangani sinyal. Artinya, ada alasan yang sangat bagus untuk tidak segera dihentikan: Ada pekerjaan pembersihan yang harus dilakukan. Jika Anda menghentikan pekerjaan pembersihan itu dengan sinyal lain, tidak ada yang tahu data apa dari memori yang belum disimpan ke disk, aplikasi klien apa yang dibiarkan hang atau apakah Anda menyela "kalimat tengah" yang secara efektif merusak data.

Untuk informasi lebih lanjut tentang arti sebenarnya dari sinyal-sinyal itu, lihat sigaction (2). Jangan bingung antara "Tindakan Default" dengan "Deskripsi", keduanya bukanlah hal yang sama.

SIGINT digunakan untuk memberi sinyal "interupsi keyboard" interaktif dari proses tersebut. Beberapa program mungkin menangani situasi ini dengan cara khusus untuk tujuan pengguna terminal.

SIGHUP digunakan untuk memberi sinyal bahwa terminal telah menghilang dan tidak lagi melihat prosesnya. Itu semuanya. Beberapa proses memilih untuk dimatikan sebagai respons, umumnya karena operasinya tidak masuk akal tanpa terminal, beberapa memilih untuk melakukan hal lain seperti memeriksa ulang file konfigurasi.

SIGKILL digunakan untuk secara paksa menghapus proses dari kernel. Ini khusus dalam arti bahwa ini sebenarnya bukan sinyal untuk proses tetapi ditafsirkan oleh kernel secara langsung.

Jangan kirim SIGKILL. SIGKILL seharusnya tidak pernah dikirim melalui skrip. Jika aplikasi menangani SIGTERM, diperlukan beberapa saat untuk membersihkan, dapat memerlukan waktu satu menit, dapat memakan waktu satu jam . Bergantung pada apa yang harus dilakukan aplikasi sebelum siap untuk diakhiri. Logika apa pun yang " mengasumsikan " urutan pembersihan aplikasi telah memakan waktu cukup lama dan perlu dipintas atau SIGKILL setelah X detik benar- benar salah .

Satu-satunya alasan mengapa aplikasi memerlukan SIGKILL untuk dihentikan, adalah jika ada sesuatu yang mengganggu selama urutan pembersihannya. Dalam hal ini Anda dapat membuka terminal dan SIGKILL secara manual. Selain itu, satu-satunya alasan lain mengapa Anda SIGKILL sesuatu adalah karena Anda INGIN mencegahnya membersihkan dirinya sendiri.

Meskipun separuh dunia secara membabi buta mengirim SIGKILL setelah 5 detik, itu masih hal yang sangat salah untuk dilakukan.

lhunath
sumber
13
Anda benar bahwa ada banyak penyalahgunaan SIGKILL di luar sana. Tetapi ada waktu dan tempat untuk menggunakannya, bahkan dari sebuah naskah. Banyak, banyak aplikasi menjebak SIGTERM dan keluar dengan anggun dalam waktu kurang dari satu detik atau hanya dalam beberapa detik, dan salah satunya masih berjalan 30 detik kemudian itu karena terjepit.
dwc
4
@dwc: Coba biarkan berjalan sekali selama satu jam. Jika tidak mati maka itu "terjepit" dan memperbaikinya, atau malas dan di masa depan SIGKILL setelah beberapa waktu. Perhatikan bahwa Anda mungkin merusak barang dan ingat bahwa ini BUKAN sesuatu yang harus Anda lakukan "secara default".
lhunath
2
@lhunath: Harap Anda tidak keberatan, paragraf Anda saya susun ulang agar jawabannya lebih langsung dan jelas mengikuti dari pertanyaan. Kata-kata kasar anti-SIGKILL adalah hal yang bagus, tetapi poin kedua. Sekali lagi terima kasih atas jawaban yang luar biasa & mendidik.
sistem JEDA
8
Jangan kirim SIGKILL. Pernah. Benar-benar salah. Betulkah? Bahkan jika sistem Anda sudah terbakar berkat loop tak terbatas. Semoga berhasil. -1
konsolebox
//, Upvoting untuk Ini konyol.
Nathan Basanese
18

Jawaban Singkat : Kirim SIGTERM, 30 detik kemudian SIGKILL,. Yaitu, kirim SIGTERM, tunggu sebentar (mungkin berbeda dari satu program ke program lainnya, Anda mungkin lebih mengenal sistem Anda, tetapi 5 hingga 30 detik sudah cukup. Saat mematikan mesin, Anda mungkin melihatnya secara otomatis menunggu hingga 1'30-an. Kenapa terburu-buru?), Lalu kirim SIGKILL.

Wajar Jawaban : SIGTERM, SIGINT, SIGKILL ini lebih dari cukup. Prosesnya kemungkinan besar akan berakhir sebelumnya SIGKILL.

Panjang Jawaban : SIGTERM, SIGINT, SIGQUIT, SIGABRT,SIGKILL

Ini tidak perlu, tetapi setidaknya Anda tidak menyesatkan proses terkait pesan Anda. Semua sinyal-sinyal yang berarti Anda ingin proses untuk menghentikan apa yang dilakukannya dan keluar.

Apa pun jawaban yang Anda pilih dari penjelasan ini, ingatlah itu!

Jika Anda mengirim sinyal yang berarti sesuatu yang lain, prosesnya mungkin menanganinya dengan cara yang sangat berbeda (di satu sisi). Di sisi lain, jika proses tidak menangani sinyal, tidak peduli apa yang Anda kirim, proses akan tetap berhenti (ketika tindakan default adalah untuk menghentikan, tentu saja).

Jadi, Anda harus berpikir sebagai diri Anda sendiri sebagai seorang programmer. Apakah Anda akan membuat kode penangan fungsi untuk, katakanlah, SIGHUPuntuk keluar dari program yang terhubung dengan sesuatu, atau apakah Anda akan mengulanginya untuk mencoba menghubungkan lagi? Itulah pertanyaan utama di sini! Itulah mengapa penting untuk hanya mengirimkan sinyal yang sesuai dengan keinginan Anda.

Jawaban Panjang yang Hampir Bodoh :

Tabel di bawah ini berisi sinyal yang relevan, dan tindakan default jika program tidak menanganinya.

Saya memesannya dalam urutan yang saya sarankan untuk digunakan (BTW, saya sarankan Anda untuk menggunakan jawaban yang masuk akal , bukan yang ini di sini), jika Anda benar-benar perlu mencoba semuanya (akan menyenangkan untuk mengatakan tabel dipesan dalam hal kehancuran yang mungkin mereka sebabkan, tetapi itu tidak sepenuhnya benar).

Sinyal dengan tanda bintang (*) TIDAK disarankan. Hal penting tentang ini adalah Anda mungkin tidak pernah tahu apa yang diprogram untuk dilakukan. Khususnya SIGUSR! Ini mungkin memulai kiamat (itu adalah sinyal gratis bagi programmer untuk melakukan apa pun yang dia inginkan!). Tapi, jika tidak ditangani ATAU dalam kasus yang tidak mungkin ditangani untuk dihentikan, program akan berhenti.

Dalam tabel, sinyal dengan opsi default untuk menghentikan dan menghasilkan core dump ditinggalkan pada akhirnya, tepat sebelumnya SIGKILL.

Signal     Value     Action   Comment
----------------------------------------------------------------------
SIGTERM      15       Term    Termination signal
SIGINT        2       Term    Famous CONTROL+C interrupt from keyboard
SIGHUP        1       Term    Disconnected terminal or parent died
SIGPIPE      13       Term    Broken pipe
SIGALRM(*)   14       Term    Timer signal from alarm
SIGUSR2(*)   12       Term    User-defined signal 2
SIGUSR1(*)   10       Term    User-defined signal 1
SIGQUIT       3       Core    CONTRL+\ or quit from keyboard
SIGABRT       6       Core    Abort signal from abort(3)
SIGSEGV      11       Core    Invalid memory reference
SIGILL        4       Core    Illegal Instruction
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal

Maka saya akan menyarankan untuk ini jawaban yang panjang hampir bodoh : SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGQUIT, SIGABRT,SIGKILL

Dan akhirnya, file

Jawaban Panjang yang Pasti Bodoh :

Jangan coba ini di rumah.

SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGALRM, SIGUSR2, SIGUSR1, SIGQUIT, SIGABRT, SIGSEGV, SIGILL, SIGFPEDan jika tidak ada yang berhasil, SIGKILL.

SIGUSR2harus dicoba sebelumnya SIGUSR1karena kita lebih baik jika program tidak menangani sinyalnya. Dan lebih mungkin untuk menangani SIGUSR1jika menangani hanya salah satu dari mereka.

BTW, the KILL : tidak salah mengirim SIGKILLke suatu proses, seperti jawaban lain yang dinyatakan. Nah, pikirkan apa yang terjadi ketika Anda mengirim shutdownperintah? Ini akan mencoba SIGTERMdan SIGKILLhanya. Menurut Anda mengapa demikian? Dan mengapa Anda membutuhkan sinyal lain, jika shutdownperintah itu hanya menggunakan dua sinyal ini?


Sekarang, kembali ke jawaban panjang , ini adalah satu kalimat yang bagus:

for SIG in 15 2 3 6 9 ; do echo $SIG ; echo kill -$SIG $PID || break ; sleep 30 ; done

Ia tidur selama 30 detik di antara sinyal. Mengapa lagi Anda membutuhkan oneliner ? ;)

Juga, disarankan: coba hanya dengan sinyal 15 2 9dari jawaban yang masuk akal .

keamanan : lepaskan detik echosaat Anda siap untuk pergi. Saya menyebutnya milik saya dry-rununtuk onliner . Selalu gunakan untuk menguji.


Script membunuh

Sebenarnya saya sangat tertarik dengan pertanyaan ini sehingga saya memutuskan untuk membuat skrip kecil untuk melakukan hal itu. Silakan, silakan unduh (klon) di sini:

Tautan GitHub ke repositori Killgracefully

DrBeco
sumber
8

Biasanya Anda akan mengirim SIGTERM, default kill. Ini default karena suatu alasan. Hanya jika sebuah program tidak ditutup dalam jangka waktu yang wajar, Anda harus melakukannya SIGKILL. Tetapi perhatikan bahwa dengan SIGKILLprogram tidak ada kemungkinan untuk membersihkan hal-hal dan data bisa rusak.

Adapun SIGHUP, HUPsingkatan dari "menutup telepon" dan secara historis berarti modem terputus. Ini pada dasarnya sama dengan SIGTERM. Alasan mengapa daemon terkadang digunakan SIGHUPuntuk memulai ulang atau memuat ulang konfigurasi adalah karena daemon terlepas dari terminal pengendali mana pun karena daemon tidak memerlukannya dan oleh karena itu tidak akan pernah menerima SIGHUP, sehingga sinyal dianggap "dibebaskan" untuk penggunaan umum. Tidak semua daemon menggunakan ini untuk memuat ulang! Tindakan default untuk SIGHUP adalah menghentikan dan banyak daemon berperilaku seperti itu! Jadi Anda tidak bisa begitu saja mengirimkan SIGHUPdaemon dan mengharapkan mereka untuk bertahan hidup.

Sunting: SIGINT mungkin tidak tepat untuk menghentikan suatu proses, karena biasanya terkait dengan ^Catau apa pun pengaturan terminal untuk mengganggu program. Banyak program menangkap ini untuk tujuan mereka sendiri, jadi cukup umum untuk tidak berhasil. SIGQUITbiasanya memiliki default untuk membuat core dump, dan kecuali Anda ingin file inti diletakkan di sekitarnya, itu juga bukan kandidat yang baik.

Ringkasan: jika Anda mengirim SIGTERMdan program tidak mati dalam jangka waktu Anda, maka kirimkan SIGKILL.

dwc
sumber
4
Perhatikan bahwa menindaklanjutinya dengan SIGKILL hanya boleh dilakukan dalam situasi di mana mematikan secara instan adalah prioritas yang lebih tinggi daripada mencegah kehilangan data / kerusakan data.
thomasrutter
@dwc Saya tidak mengerti poin berikut dalam jawaban Anda. bisakah Anda membantu "Alasan mengapa daemon terkadang menggunakan SIGHUP untuk memulai ulang atau memuat ulang konfigurasi adalah karena daemon terlepas dari terminal pengontrol mana pun dan karena itu tidak akan pernah menerima SIGTERM, sehingga sinyal dianggap" dibebaskan "untuk penggunaan umum."
Jack
3
@ Jack Izinkan saya mencoba: SIGHUP adalah sinyal "tutup" yang memberitahukan proses bahwa terminal telah terputus. Karena daemon berjalan di latar belakang, mereka tidak membutuhkan terminal. Itu berarti sinyal "tutup" tidak relevan dengan daemon. Mereka tidak akan pernah menerimanya dari pemutusan terminal, karena mereka tidak memiliki terminal yang terhubung sejak awal. Dan karena sinyal tetap didefinisikan, meskipun mereka tidak membutuhkannya untuk tujuan aslinya, banyak daemon yang menggunakannya untuk tujuan yang berbeda, seperti membaca ulang file konfignya.
sistem JEDA
Terima kasih sistem JEDA. ini berguna.
Jack
7

SIGTERMsebenarnya berarti mengirim pesan ke aplikasi: " maukah kamu menjadi begitu baik dan bunuh diri ". Itu bisa terjebak dan ditangani oleh aplikasi untuk menjalankan kode pembersihan dan shutdown.

SIGKILLtidak bisa terjebak oleh aplikasi. Aplikasi dimatikan oleh OS tanpa ada kesempatan untuk dibersihkan.

Biasanya mengirim SIGTERMdulu, tidur sebentar, lalu mengirim SIGKILL.

vartec
sumber
Saya kira pemungutan suara akan sedikit lebih efisien daripada tidur (sebelum SIGKILL)
Ohad Schneider
@OhadSchneider akan melakukannya, tetapi itu akan membutuhkan sesuatu yang lebih dari sekadar perintah bash.
vartec
Ya, saya kira Anda perlu melakukan loop saat proses masih hidup menggunakan sesuatu seperti ini: stackoverflow.com/a/15774758/67824 .
Ohad Schneider
5
  • SIGTERM sama dengan "mengklik 'X'" di jendela.
  • SIGTERM adalah yang pertama digunakan Linux, ketika sedang dimatikan.
gbarry
sumber
Itulah yang ingin saya ketahui. +1. Terima kasih.
Luc
6
"SIGTERM sama dengan" mengklik 'X' "di jendela" Tidak, tidak, karena salah satu aplikasi dapat dengan mudah membuka sejumlah jendela (dokumen dan alat, misalnya), apalagi dialog, dan mungkin tidak bahkan menanggapi perintah tutup jendela terakhir seperti halnya perintah keluar (saya tidak dapat memikirkan contoh yang jelas, tetapi meskipun tidak jelas, tidak ada alasan mengapa hal itu tidak dapat dilakukan seperti itu). SIGTERM adalah (atau seharusnya) setara dengan meminta aplikasi untuk dihentikan dengan baik, namun itu mungkin dilakukan dalam aplikasi tersebut .
pengguna
3

Dengan semua diskusi yang berlangsung di sini, tidak ada kode yang ditawarkan. Ini pendapat saya:

#!/bin/bash

$pid = 1234

echo "Killing process $pid..."
kill $pid

waitAttempts=30 
for i in $(seq 1 $waitAttempts)
do
    echo "Checking if process is alive (attempt #$i / $waitAttempts)..."
    sleep 1

    if ps -p $pid > /dev/null
    then
        echo "Process $pid is still running"
    else
        echo "Process $pid has shut down successfully"
        break
    fi
done

if ps -p $pid > /dev/null
then
    echo "Could not shut down process $pid gracefully - killing it forcibly..."
    kill -SIGKILL $pid
fi
Ohad Schneider
sumber
0

HUP terdengar seperti sampah bagi saya. Saya akan mengirimkannya agar daemon membaca ulang konfigurasinya.

SIGTERM dapat dicegat; daemon Anda mungkin memiliki kode pembersihan untuk dijalankan ketika menerima sinyal itu. Anda tidak dapat melakukan itu untuk SIGKILL. Jadi dengan SIGKILL Anda tidak memberikan opsi apa pun kepada pembuat daemon.

Lebih lanjut tentang itu di Wikipedia

innaM
sumber