[apue] 使用 Ctrl+S停止輸出而不用掛起前臺進程

来源:https://www.cnblogs.com/goodcitizen/archive/2020/01/25/12233461.html
-Advertisement-
Play Games

之前一直知道使用 Ctrl+Z 掛起前臺進程來阻止進程運行,之後可以再通過 shell 的作業控制 (jobs / fg N) 來將後臺進程切換為前臺,從而繼續運行。 最近學到一種新的方法,對於不停有 console 輸出的前臺進程,可以使用 Ctrl+S 來 STOP 一個進程的輸出,從而暫停進程 ...


之前一直知道使用 Ctrl+Z 掛起前臺進程來阻止進程運行,之後可以再通過 shell 的作業控制 (jobs / fg N) 來將後臺進程切換為前臺,從而繼續運行。

最近學到一種新的方法,對於不停有 console 輸出的前臺進程,可以使用 Ctrl+S 來 STOP 一個進程的輸出,從而暫停進程。

之後可以通過 Ctrl+Q 或輸入任意字元來重啟 (START) 進程輸出,從而繼續運行。

 

看到這個方法,立即想到寫個腳本驗證一下:

deadloop.sh

1 #! /bin/sh
2 var=1
3 while :
4 do
5   echo this is $var
6   var=$(($var+1))
7   usleep 100000
8 done

 

這個腳本每 100 毫秒輸出一條日誌 “this is N”,其中 N 為日誌序號,可以幫我們確定在一次暫停與重啟之間,是否有輸出丟失。

運行過程中按下 Ctrl+S,輸出果然暫停了:

>./deadloop.sh 
this is 1
this is 2
this is 3
this is 4

 

 

再按下 Ctrl+Q 則輸出繼續,直到按下 Ctrl+Z 掛起進程:

>./deadloop.sh 
this is 1
this is 2
this is 3
this is 4
this is 5
this is 6
this is 7
this is 8
this is 9
this is 10
this is 11
^Z
[1]+  Stopped                 ./deadloop.sh
>

 

 

首先可以看到重啟後的輸出序號與重啟前的可以接上,所以中間並沒有輸出丟失,也就是說是進程被暫停了,而不只是輸出停止了。

其次在按下 Ctrl+Z 時終端會回顯 ^Z,而按下 Ctrl+S 或 Ctrl+Q 時,終端沒有任何回顯。

 

於是重點對比按下 Ctrl+S 時與 Ctrl+Z 時進程的狀態,來看這兩種暫停方式的區別。

通過 ps 命令查看下兩種暫停時進程的狀態:

Ctrl+S

>ps xfo pid,ppid,pgid,sid,tpgid,suid,euid,user,stat,tty,command
PID PPID PGID SID TPGID SUID EUID USER STAT TT COMMAND 6653 6652 2786 2786 -1 500 500 yunhai S ? \_ gnome-pty-helper 6655 6652 6655 6655 6655 500 500 yunhai Ss+ pts/0 \_ /bin/bash 12539 6652 12539 12539 16673 500 500 yunhai Ss pts/1 \_ /bin/bash 16673 12539 16673 12539 16673 500 500 yunhai S+ pts/1 | \_ /bin/sh ./deadloop.sh 12797 6652 12797 12797 13349 500 500 yunhai Ss pts/2 \_ /bin/bash 15959 6652 15959 15959 16766 500 500 yunhai Ss pts/3 \_ /bin/bash 16766 15959 16766 15959 16766 500 500 yunhai R+ pts/3 \_ ps xfo pid,ppid,pgid,sid,tpgid,suid,euid,user,stat,tty,command

  

Ctrl+Z

>ps xfo pid,ppid,pgid,sid,tpgid,suid,euid,user,stat,tty,command
  PID  PPID  PGID   SID TPGID  SUID  EUID USER     STAT TT       COMMAND
 6653  6652  2786  2786    -1   500   500 yunhai   S    ?         \_ gnome-pty-helper
 6655  6652  6655  6655  6655   500   500 yunhai   Ss+  pts/0     \_ /bin/bash
12539  6652 12539 12539 16717   500   500 yunhai   Ss   pts/1     \_ /bin/bash
16673 12539 16673 12539 16717   500   500 yunhai   T    pts/1     |   \_ /bin/sh ./deadloop.sh
16688 16673 16673 12539 16717   500   500 yunhai   T    pts/1     |   |   \_ usleep 100000
16717 12539 16717 12539 16717   500   500 yunhai   R+   pts/1     |   \_ ps xfo pid,ppid,pgid,sid,tpgid,suid,euid,user,stat,tty,command
12797  6652 12797 12797 13349   500   500 yunhai   Ss   pts/2     \_ /bin/bash
15959  6652 15959 15959 15959   500   500 yunhai   Ss+  pts/3     \_ /bin/bash

 

 

可以看到最大的不同是,通過 Ctrl+Z 停止的進程狀態為掛起 ('T'),而通過 Ctrl+S 停止的進程狀態為運行 ('S+')。

另一方面,我們啟動 stap 探測進程間信號的收發,可以在 Ctrl+Z 停止進程時收到以下的輸出:

stap_signal.sh

22       events/3         16688 usleep           20     SIGTSTP         
22       events/3         16673 deadloop.sh      20     SIGTSTP        
16673    deadloop.sh      12539 bash             17     SIGCHLD        
16688    usleep           16673 deadloop.sh      17     SIGCHLD 

 

 

也就是說可以觀察到向前臺進程發送的 SIGTSTP 信號。而在使用 Ctrl+S 時並無特別的信號被偵測到 (僅 usleep 進程結束時向父進程發送的 SIGCHILD)。

 

註意:此處的 SIGCHLD 並不表示 deadloop.sh 與 usleep 結束,而是掛起時向父進程發送的通知。關於這一點,可以參考我之前寫的一篇文章:

[apue] 等待子進程的那些事兒

 

在暫停期間,通過 pstack 命令查看兩種方式暫停的進程堆棧信息:

Ctrl+S

>pstack 16673
#0  0x00119424 in __kernel_vsyscall ()
#1  0x007a7cd3 in __write_nocancel () from /lib/libc.so.6
#2  0x007411b4 in _IO_new_file_write () from /lib/libc.so.6
#3  0x00742a90 in _IO_new_do_write () from /lib/libc.so.6
#4  0x00741c80 in _IO_new_file_overflow () from /lib/libc.so.6
#5  0x00744b2a in __overflow () from /lib/libc.so.6
#6  0x0073e0b5 in putc () from /lib/libc.so.6
#7  0x080aebb0 in echo_builtin ()
#8  0x08070c51 in ?? ()
#9  0x08072e41 in ?? ()
#10 0x08073aa0 in execute_command_internal ()
#11 0x080747a4 in execute_command ()
#12 0x08076d89 in ?? ()
#13 0x08073a02 in execute_command_internal ()
#14 0x080747a4 in execute_command ()
#15 0x08076d89 in ?? ()
#16 0x08073a02 in execute_command_internal ()
#17 0x080747a4 in execute_command ()
#18 0x080750e4 in ?? ()
#19 0x08073bc4 in execute_command_internal ()
#20 0x080747a4 in execute_command ()
#21 0x08060857 in reader_loop ()
#22 0x0805fed9 in main ()

 

 

Ctrl+Z

>pstack 16673
#0  0x00119424 in __kernel_vsyscall ()
#1  0x00776673 in __waitpid_nocancel () from /lib/libc.so.6
#2  0x080830f2 in ?? ()
#3  0x0808432e in wait_for ()
#4  0x08074635 in execute_command_internal ()
#5  0x08076dcd in ?? ()
#6  0x08073a02 in execute_command_internal ()
#7  0x080747a4 in execute_command ()
#8  0x080750e4 in ?? ()
#9  0x08073bc4 in execute_command_internal ()
#10 0x080747a4 in execute_command ()
#11 0x08060857 in reader_loop ()
#12 0x0805fed9 in main ()

 

 

前者停止在了 write 系統調用,後者停止在了 waitpid 系統調用。

所以前者應該是在輸出時被暫停的,而後者是在等待 usleep 子進程返回時被掛起的。

大家可以體會一下這兩處方式在細微處的差別。

 

最後,可以使用 Ctrl+S 停止前臺進程的前提是 必需打開終端的 IXON 標誌,使用之前的小工具:

[apue] 一個查看當前終端標誌位設置的小工具

 

可以查看終端的輸入 flag 是否已經打開了這個標誌:

>./term
input flag 0x00006f02
    BRKINT
    ICRNL
    IMAXBEL
    IXANY
    IXON
output flag 0x00000005
    ONLCR
    OPOST
control flag 0x000004bf
    CREAD
    CSIZE
    CS6
    CS7
    CS8
    HUPCL
local flag 0x00008a3b
    ECHO
    ECHOE
    ECHOK
    ICANON
    IEXTEN
    ISIG

 

 

一般終端都是打開的。如果再打開 IXANY 標誌位,則使用任意鍵都可以重啟被停止的輸出,而不一定要使用 Ctrl+Q。

最後,還有一個隱藏的前提,就是被暫停的進程在前臺有頻繁的輸出,否則 Ctrl+S 也無用武之地。

 

總結一下,今天學到一個新的方法去暫停運行中的前臺進程,可能對於運維老鳥來說已經是手到擒來,對我卻是完全的新鮮,

所以花了些時間研究下,感覺 linux 博大精深,不起眼處可能就藏著一些好東西,值得挖掘!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在項目當中資料庫一般都會成為主要的性能與負載瓶頸,那麼針對資料庫各項性能指標的監控與對應的優化是開發與運維人員需要面對的主要工作,而且這部分的工作會貫穿項目從開發到運行的整個周期里。 這篇文章中我們對MySql資料庫中的幾個主要的性能指標的計算與統計進行下說明與總結。 在MySql中通過show g ...
  • 大數據環境需要的安裝包合集,包括: apache flume 1.7.0 bin.tar.gz apache hive 1.2.1 bin.tar.gz hadoop 2.7.2.tar.gz hbase 1.3.1 bin.tar.gz jdk 8u144 linux x64.tar kafka_ ...
  • 前言 Stanley B.Lippman 先生所著的《C++ Primer》是學習C++的一本非常優秀的教科書,但《C++ Primer》作為一本大部頭書,顯然不適合所有的初學者。所以Lippman先生又返璞歸真地寫了這本短小輕薄的《Essentia C++》。這本書以簡短的章節篇幅,幫助初學者快速... ...
  • MyBatis MyBatis是Apache的一個開源項目iBatis, iBatis一詞來源於“internet”和“abatis”的組合,是一個基於Java的持久層框架。 iBatis 提供的持久層框架包括SQL Maps和Data Access Objects(DAO) Mybatis 是一個 ...
  • 內容有點多,請耐心! 最近公司的有這個業務需求,又很湊巧讓我來完成: 首先想要對接,先要一個公眾號,再就是開發文檔了:https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html 不過請註意這一點 ok, ...
  • 微信公眾號: "Dotnet9" ,網站: "Dotnet9" ,問題或建議: "請網站留言" , 如果對您有所幫助: "歡迎贊賞" 。 .NET CORE(C ) WPF 方便的實現用戶控制項切換(祝大家新年快樂) 快到2020年了,祝大家新年快樂,今年2019最後一更,謝謝大家支持! 閱讀導航 1 ...
  • .NET基金會是一個獨立的非營利組織,於2014年成立,旨在圍繞 .NET 不斷增長的開源技術集合,促進開放開發和協作。它是商業和社區開發人員的論壇,通過促進開放性,社區參與和快速創新來增強.NET生態系統的未來。要使.NET 基金會真正獨立並由社區運營,則需要獨立資助。過去,.NET 基金會依靠來... ...
  • 【五分鐘的dotnet】是一個利用您的碎片化時間來學習和豐富.net知識的博文系列。如果您現在正在使用.NetCore的話,相信您對await 和 async這兩個關鍵字再熟悉不過了。它們是為非同步編程提供的語法糖,便於我們在代碼中更便捷的進行非同步操作。await 和 async其實是對Task對象都... ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...