Tại sao quá trình của tôi vẫn chạy sau khi tôi đăng xuất?


10

Sau khi đăng nhập thông qua ssh, tôi gõ lệnh này vào bash:

sleep 50000000000000 &

Sau đó, tôi kill -9sleepquá trình cha mẹ của quá trình (tức là bash). Sau đó, cửa sổ đầu cuối ngắt kết nối đồng thời.

Khi tôi đăng nhập lại, tôi thấy rằng sleepquá trình này vẫn còn sống.

Câu hỏi : Tại sao sleepquá trình có thể tồn tại khi tôi đăng xuất và thiết bị đầu cuối bị đóng? Trong tâm trí của tôi, tất cả mọi thứ trừ daemon và nohupchương trình sẽ bị giết trong quá trình đăng xuất. Nếu sleepcó thể tồn tại theo cách này, điều đó có nghĩa là tôi có thể sử dụng phương pháp này thay vì nohuplệnh?


3
&sẽ rẽ nhánh quá trình sang nền (như daemon) và tiếp tục chạy cho đến khi bạn đăng xuất.
Aizuddin Zali

Câu trả lời:


6

Tl; dr:

Tại sao sleepquá trình có thể tồn tại khi tôi đăng xuất và thiết bị đầu cuối bị đóng? Trong tâm trí của tôi, tất cả mọi thứ trừ daemon và nohupchương trình sẽ bị giết trong quá trình đăng xuất. Nếu sleepcó thể tồn tại theo cách này, điều đó có nghĩa là tôi có thể sử dụng phương pháp này thay vì nohuplệnh?

Trừ khi bashcá thể được sinh ra bởi sshhuponexittùy chọn được đặt, sẽ không có quá trình nào bị chấm dứt bởi bất kỳ phương tiện nào khi thoát / đăng xuất và khi huponexittùy chọn được đặt, sử dụng kill -9trên shell không phải là cách thay thế tốt cho việc sử dụng nohuptrên các tiến trình con của shell; nohuptrên các quy trình con của shell vẫn sẽ bảo vệ chúng khỏi SIGHUP không xuất phát từ shell và ngay cả khi điều đó không quan trọng nohupvẫn được ưu tiên vì nó cho phép shell được kết thúc một cách duyên dáng.


Trong bashđó có một tùy chọn được gọi huponexit, nếu được đặt sẽ tạo bashSIGHUP con của nó khi thoát / đăng xuất;

Trong các bash trường hợp không đăng nhập tương tác , chẳng hạn như trong một bashtrường hợp được sinh ra bởi gnome-terminal, tùy chọn này bị bỏ qua; dù huponexitđược đặt hay không được đặt, bashtrẻ em sẽ không bao giờ bị SIGHUPped bashkhi thoát;

Trong các trường hợp đăng nhập tương tác bash, chẳng hạn như trong một bashtrường hợp được sinh ra bởi ssh, tùy chọn này không bị bỏ qua (tuy nhiên nó không được đặt theo mặc định); nếu huponexitđược đặt, bashcon cái sẽ bị SIGHUPped bashkhi thoát / đăng xuất; nếu không huponexitđược đặt, bashtrẻ em sẽ không bị SIGHUPped bashkhi thoát / đăng xuất;

Vì vậy, trong việc thoát / đăng xuất chung từ một bashcá thể đăng nhập tương tác , trừ khi huponexittùy chọn được đặt, sẽ không tạo vỏ SIGHUP con của nó và thoát / đăng xuất khỏi một bashcá thể không đăng nhập tương tác sẽ không tạo vỏ SIGHUP con của nó bất kể;

Tuy nhiên, điều này không liên quan trong trường hợp này: sử dụng kill -9 sleepsẽ tồn tại bất kể vì việc giết tiến trình cha mẹ của nó ( bash) sẽ không để lại cơ hội cho người sau làm bất cứ điều gì với ví dụ trước (ví dụ: nếu bashtrường hợp hiện tại là bashtrường hợp đăng nhập và huponexittùy chọn đã được đặt, thành SIGHUP nó).

Thêm vào đó, không giống như các tín hiệu khác (như tín hiệu SIGHUP được gửi đến bash), tín hiệu SIGKILL không bao giờ được truyền đến các tiến trình con của quy trình, do đó sleepthậm chí không bị giết;

nohupbắt đầu một quá trình miễn dịch với các tín hiệu SIGHUP, một cái gì đó khác biệt; nó sẽ ngăn quá trình treo lên khi nhận tín hiệu SIGHUP, trong trường hợp này có thể nhận được bằng thể hiện đăng nhập tương tác bashtrong trường hợp huponexittùy chọn được đặt và thoát vỏ; Vì vậy, về mặt kỹ thuật sử dụng nohupđể bắt đầu một quy trình trong bashtrường hợp đăng nhập tương tác với huponexittùy chọn không được đặt sẽ ngăn quá trình treo lên khi nhận tín hiệu SIGHUP, nhưng việc thoát / đăng xuất khỏi vỏ sẽ không SIGHUP bất kể;

Tuy nhiên, nói chung, khi nohupcần thiết để ngăn chặn tín hiệu SIGHUP đến từ vỏ cha, không có lý do nào để thích kill -9phương thức cha mẹ hơn phương thức nohupcon; thay vào đó, nó phải ngược lại.

Giết cha mẹ bằng kill -9phương pháp không để cho cha mẹ thoát ra một cách duyên dáng, trong khi bắt đầu con sử dụng nohupphương thức này cho phép cha mẹ bị chấm dứt bởi các tín hiệu khác, chẳng hạn như SIGHUP (để làm ví dụ có ý nghĩa trong ngữ cảnh của một đứa trẻ bắt đầu sử dụng nohup), cho phép nó thoát ra một cách duyên dáng.


Nói cách khác, nếu tôi có một tập lệnh được đặt trong nền, nó vẫn sẽ chạy ngay cả khi tôi giết tiến trình cha, ví dụ shell của tôi phải không? Điều gì sẽ là một cách để giết chết kịch bản đó?
Sergiy Kolodyazhnyy

@Serg Nếu bạn có PID, chỉ cần giết PID; nếu bạn không lưu trữ PID nhưng bạn có thể xác định quy trình theo tên của anh ấy, ps -e | grep processnên liệt kê các quy trình cùng với PID (hoặc tốt hơn là pgrep -x processnếu bạn chắc chắn khớp quy trình đơn lẻ đó và không phải là những thứ không được phép); vấn đề là khi bạn giết một quá trình với kill -9những đứa con của nó bị sở hữu upstart, do đó PPID ban đầu của chúng bị mất và PPID của chúng thay đổi để khởi động PID, khiến chúng không thể nhận ra (AFAIK) nhưng vì tên của chúng hoặc PID
kos

@kos Trong điều kiện nào nohupsẽ không thể ngăn quá trình treo lên khi nhận được tín hiệu SIGHUP từ quy trình cha? Tôi đang cố gắng chạy một quá trình trong nền (trong thiết bị đầu cuối vỏ PuTTY SSH) nohup <command> <arg> &. Khi tôi đăng xuất bằng cách nhấp vào Xnút PuTTY , quá trình nền sẽ chấm dứt ngay lập tức. Khi tôi đăng xuất bằng cách nhập exitvào thiết bị đầu cuối vỏ PuTTY SSH, quá trình sẽ tiếp tục chạy trong nền.
userpal

3

bashtheo mặc định không gửi tín hiệu HUP xuống các tiến trình con khi thoát . Chi tiết hơn (cảm ơn @kos), nó không bao giờ làm điều đó cho các shell không đăng nhập .

Bạn có thể cấu hình bash để làm điều đó cho shell đăng nhập nếu đặt tùy chọn huponexit. Trong một thiết bị đầu cuối, làm:

[romano:~] % bash -l

(điều này bắt đầu một vỏ "đăng nhập" mới)

romano@pern:~$ shopt -s huponexit
romano@pern:~$ sleep 1234 &
[1] 32202
romano@pern:~$ exit
logout

Bây giờ hãy kiểm tra sleepquá trình:

[romano:~] % ps augx | grep sleep
romano   32231  0.0  0.0  16000  2408 pts/11   S+   15:23   0:00 grep sleep

... không chạy: nó đã nhận được tín hiệu HUP và thoát theo yêu cầu.


@kos --- vâng, bạn đúng nhưng ... vậy tại sao nếu tôi sleep 1000 & ; exitlà người sleepsống sót? Chú ý rằng nếu tôi kill -HUPsleepxử lý nó sẽ thoát. Và ngay cả khi huponexitđược thiết lập, những người sleepsống sót. Bối rối ... (Tôi sẽ cố gắng hiểu rõ hơn và sửa đổi asnwer, nếu không tôi sẽ xóa nó).
Rmano

2

Nếu sleepcó thể tồn tại theo cách này, nếu nó có nghĩa là tôi có thể sử dụng phương pháp này thay vì nohuplệnh?

kill -9thực sự không phải là con đường nên đi Nó giống như bắn bằng súng vào TV để tắt nó đi. Bên cạnh thành phần hài không có lợi thế. Các quy trình không thể bắt hoặc bỏ qua SIGKILL. Nếu bạn không cho quá trình hoàn thành những gì nó đang làm và dọn sạch, nó có thể để lại các tệp bị hỏng (hoặc trạng thái khác) xung quanh và sẽ không thể bắt đầu lại. kill -9là hy vọng cuối cùng, khi không có gì khác hoạt động.


Tại sao quá trình ngủ có thể tồn tại khi tôi đăng xuất và thiết bị đầu cuối bị đóng. Trong tâm trí của tôi, tất cả mọi thứ trừ daemon và chương trình nohup sẽ bị giết khi đăng xuất.

Điều gì trong trường hợp của bạn xảy ra:

Quá trình cha của sleepbashshell hiện đang chạy . Khi bạn kill -9bash đó, quy trình bash không có cơ hội gửi một SIGHUPđến bất kỳ quy trình con nào của nó, bởi vì SIGKILL( quy trình được gửi bởi kill -9) không thể bắt được bởi quy trình. Quá trình ngủ tiếp tục chạy. giấc ngủ bây giờ đã trở thành một quá trình mồ côi .

Quá trình init (PID 1) thực hiện một cơ chế gọi là reparenting. Điều đó có nghĩa là quy trình init bây giờ trở thành cha mẹ của quá trình mồ côi đó. init là một ngoại lệ, các tiến trình có thể trở thành con của nó vì nó thu thập các tiến trình bị mất tiến trình cha mẹ ban đầu của chúng. Btw: Một daemon (như sshd) làm điều đó khi "đi trong nền".

Nếu điều đó không xảy ra, quá trình mồ côi sau này (khi kết thúc) sẽ trở thành quá trình zombie. Đây là những gì xảy ra khi waitpid()không được gọi (trách nhiệm của quy trình cha không thể hoàn thành khi quy trình đó bị giết). init gọi waitpid()trong một intervall cụ thể để tránh zombie trẻ em.


Quá trình này vẫn tồn tại ngay cả với các tín hiệu lịch sự như TERMhoặcHUP
heemayl

@heemayl HUP phụ thuộc vào cấu hình shell : huponext. Và HẠN sẽ đợi đến khi ngủ xong. Trong trường hợp lệnh ngủ của OP, nó sẽ là hàng ngàn năm =)
hỗn loạn

1

Việc &bắt đầu quá trình trong nền. Nếu bạn nhập ps -ef, bạn sẽ thấy ID tiến trình cha mẹ (PPID) của giấc ngủ là bash của bạn. Sau đó đăng xuất và đăng nhập lại. Quá trình sẽ vẫn chạy sau khi bạn đăng xuất. Sau khi bạn đăng nhập lần thứ hai, bạn chạy ps -eflại. Bạn sẽ thấy rằng bây giờ cha mẹ của quá trình ngủ của bạn sẽ được xử lý với id "1". Đó là init, cha mẹ của tất cả các quá trình.


0

Sử dụng &sẽ khiến chương trình chạy làm nền. Để xem chương trình trong nền, hãy sử dụng bglệnh và để làm cho nó chạy như tiền cảnh một lần nữa, hãy chạy fg.

Có, có nhiều cách để giữ cho chương trình chạy ngay cả khi thiết bị đầu cuối chính đã thoát.


cảm ơn. trang man của bash hơi khó hiểu. Nó nói rằng: "Trước khi xuất cảnh, một vỏ tương tác sẽ gửi lại các SIGHUP cho tất cả các công việc, chạy hoặc dừng lại." Nhưng trong thực tế, vỏ chỉ gửi SIGHUP đến forground việc làm. các quá trình nền không có cơ hội nhận tín hiệu SIGHUP (trừ khi thay đổi tùy chọn vỏ 'huponexit')
tom_cat

@kos có lẽ bạn đúng. Tôi rút ra kết luận trên từ bài đăng này: stackoverflow.com/questions/4298741/ bây giờ, tôi càng bối rối hơn.
tom_cat

@tom_cat Quay lại vấn đề này một lần nữa, suy nghĩ về nó hai lần: đơn giản là không có trường hợp nào vỏ có thể thoát ra với quá trình tiền cảnh đang chạy, nó có thể bị SIGHUPped hoặc một cái gì đó, nhưng điều đó không thoát ra . Vì vậy, đó là chính xác, nó chỉ áp dụng cho các quá trình nền, bởi vì ngược lại sẽ không có ý nghĩa. Tuy nhiên, từ nghiên cứu sâu hơn, tâm trí cũng huponexitchỉ hoạt động trên các vỏ đăng nhập, chẳng hạn như một vỏ được lấy thông qua ssh(và không, giả sử, trong một vỏ được lấy qua gnome-terminal)
kos
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.