Process 模組
模組 Process
代表底層作業系統中的一個進程。其方法支持當前進程及其子進程的管理。
進程創建¶ ↑
以下每個方法都在新進程或子殼中執行給定的命令,或在新進程和/或子殼中執行多個命令。進程或子殼的選擇取決於命令的形式;請參閱參數 command_line 或 exe_path。
-
Process.spawn
,Kernel#spawn
:執行命令;返回新的 pid 而不等待完成。 -
Process.exec
:通過執行命令替換當前進程。
另外
-
方法
Kernel#system
在子殼中執行給定的命令行(字符串);返回true
、false
或nil
。 -
方法
Kernel#`
在子殼中執行給定的命令行(字符串);返回其 $stdout 字符串。 -
模組
Open3
支援建立具有存取其 $stdin、$stdout 和 $stderr 流的子處理程序。
執行環境¶ ↑
可選的前導參數 env
是一個名稱/值對的哈希,其中每個名稱都是字符串,每個值都是字符串或 nil
;每個名稱/值對都會添加到新進程中的 ENV
。
Process.spawn( 'ruby -e "p ENV[\"Foo\"]"') Process.spawn({'Foo' => '0'}, 'ruby -e "p ENV[\"Foo\"]"')
輸出
"0"
效果通常類似於調用帶有參數 env
的 ENV#update 方法,其中每個命名環境變量都被創建或更新(如果值是非 nil
),或者被刪除(如果值是 nil
)。
但是,如果新進程失敗,則對調用進程的某些修改可能仍然存在。例如,硬資源限制不會恢復。
參數 command_line
或 exe_path
¶ ↑
必需的字符串參數是以下之一
-
如果它以 shell 保留字開頭或包含一個或多個元字符,則為
command_line
。 -
否則為
exe_path
。
參數 command_line
字符串參數 command_line
是要傳遞給 shell 的命令行;它必須以 shell 保留字開頭,以特殊內建開頭,或包含元字符
system('if true; then echo "Foo"; fi') # => true # Shell reserved word. system('echo') # => true # Built-in. system('date > /tmp/date.tmp') # => true # Contains meta character. system('date > /nop/date.tmp') # => false system('date > /nop/date.tmp', exception: true) # Raises RuntimeError.
命令行還可以包含用於該命令的參數和選項
system('echo "Foo"') # => true
輸出
Foo
有關 shell 的詳細信息,請參見 Execution Shell。
參數 exe_path
參數 exe_path
是以下之一
-
要調用的可執行文件的字符串路徑。
-
包含要調用的可執行文件的路徑和要用作執行進程名稱的字符串的 2 元素數組。
示例
system('/usr/bin/date') # => true # Path to date on Unix-style system. system('foo') # => nil # Command failed.
輸出
Mon Aug 28 11:43:10 AM CDT 2023
執行選項¶ ↑
可選的尾隨參數 options
是一個執行選項的哈希。
工作目錄(:chdir
)¶ ↑
默認情況下,新進程的工作目錄與當前進程的相同。
Dir.chdir('/var') Process.spawn('ruby -e "puts Dir.pwd"')
輸出
/var
使用選項 :chdir
設置新進程的工作目錄。
Process.spawn('ruby -e "puts Dir.pwd"', {chdir: '/tmp'})
輸出
/tmp
目前進程的工作目錄不會改變。
Dir.pwd # => "/var"
文件重定向(文件描述符)¶ ↑
在新進程中使用執行選項進行文件重定向。
這樣一個選項的關鍵可以是一個整數文件描述符(fd),指定一個來源,或是一個fds數組,指定多個來源。
整數源fd可以被指定為
-
n: 指定文件描述符n。
有以下這些用於fds的速記符號
-
:in
: 指定文件描述符0(標準輸入)。 -
:out
: 指定文件描述符1(標準輸出)。 -
:err
: 指定文件描述符2(標準錯誤)。
來源給定的值之一是
-
n: 重定向到父進程中的fdn。
-
filepath
: 通過open(filepath, mode, 0644)
從或到位於filepath
的文件重定向,其中mode
是'r'
用於源:in
,或'w'
用於源:out
或:err
。 -
[filepath]
: 通過open(filepath, 'r', 0644)
從文件filepath
進行重定向。 -
[filepath, mode]
: 通過open(filepath, mode, 0644)
從或到位於filepath
的文件進行重定向。 -
[filepath, mode, perm]
: 通過open(filepath, mode, perm)
從或到位於filepath
的文件進行重定向。 -
[:child, fd]
: 重定向到被重定向的fd
。 -
:close
: 在子進程中關閉文件描述符。
環境變數(:unsetenv_others
)¶ ↑
默認情況下,新進程從父進程繼承環境變數;使用執行選項鍵:unsetenv_others
與值true
清除新進程中的環境變數。
執行選項env
指定的任何更改都是在新進程繼承或清除其環境變數之後進行的;參見執行環境。
文件創建訪問(:umask
)¶ ↑
使用執行選項:umask
來設置新進程的文件創建訪問權限;參見存取模式
command = 'ruby -e "puts sprintf(\"0%o\", File.umask)"' options = {:umask => 0644} Process.spawn(command, options)
輸出
0644
進程組(:pgroup
和:new_pgroup
)¶ ↑
默認情況下,新進程屬於與父進程相同的進程組。
指定不同的處理程序組,可使用執行選項:pgroup
並選擇以下其中一個值:
-
true
: 為新的處理程序建立一個新的處理程序組。 -
pgid: 將新的處理程序建立在 ID 為pgid的處理程序組中。
僅在 Windows 上,使用執行選項:new_pgroup
並設置值為true
以為新的處理程序建立一個新的處理程序組。
資源限制¶ ↑
使用執行選項來設定資源限制。
這些選項的鍵是符號,形式為:rlimit_resource_name
,其中resource_name是描述於方法Process.setrlimit
中的字串資源名稱的小寫形式。例如,鍵:rlimit_cpu
對應到資源限制'CPU'
。
這樣的鍵的值為以下之一:
-
一個整數,指定當前和最大限制。
-
一個包含兩個整數元素的陣列,指定當前和最大限制。
檔案描述符繼承¶ ↑
預設情況下,新的處理程序從父處理程序繼承檔案描述符。
使用執行選項:close_others => true
來修改繼承行為,即關閉非標準檔案描述符(大於3的檔案描述符),除非已經以其他方式重新導向。
執行外殼¶ ↑
在類Unix系統上,所呼叫的外殼是/bin/sh
;否則,所呼叫的外殼由環境變數ENV['RUBYSHELL']
(如果已定義)決定,否則由ENV['COMSPEC']
決定。
除了COMSPEC
情況外,整個字串command_line
都被作為引數傳遞給shell option -c。
外殼對命令行執行正常的外殼展開。
spawn('echo C*') # => 799139 Process.wait # => 799139
輸出
CONTRIBUTING.md COPYING COPYING.ja
這裡有什麼¶ ↑
當前處理程序的取得器¶ ↑
-
::argv0
: 將處理程序名稱返回為凍結的字串。 -
::egid
: 返回有效群組 ID。 -
::euid
: 返回有效用戶 ID。 -
::getpgrp
: 返回處理程序組 ID。 -
::getrlimit
: 返回資源限制。 -
::gid
:返回(實際)群組 ID。 -
::pid
:返回進程 ID。 -
::ppid
:返回父進程的進程 ID。 -
::uid
:返回(實際)用戶 ID。
當前進程設置器¶ ↑
-
::egid=
:設置有效群組 ID。 -
::euid=
:設置有效用戶 ID。 -
::gid=
:設置(實際)群組 ID。 -
::setproctitle
:設置進程標題。 -
::setpgrp
:將進程的進程組 ID 設置為零。 -
::setrlimit
:設置資源限制。 -
::setsid
:將進程設置為新的會話和進程組領導者,並且沒有控制終端。 -
::uid=
:設置用戶 ID。
當前進程執行¶ ↑
-
::abort
:立即終止進程。 -
::daemon
:將進程從其控制終端分離並在後台作為系統守護程序繼續運行。 -
::exec
:通過運行給定的外部命令來替換進程。 -
::exit
:通過引發異常SystemExit
(可能被捕獲)來啟動進程終止。 -
::exit!
:立即退出進程。 -
::warmup
:通知 Ruby 虛擬機完成應用程序的啟動序列,並且虛擬機可以開始優化應用程序。
子進程¶ ↑
-
::detach
:防止子進程變成殭屍。 -
::fork
:創建一個子進程。 -
::kill
:向進程發送給定信號。 -
::spawn
:創建一個子進程。 -
::wait2
、::waitpid2
:等待子進程退出;返回其進程 ID 和狀態。 -
::waitall
:等待所有子進程退出;返回它們的進程 ID 和狀態。
處理程序群組¶ ↑
-
::getpgid
:返回進程的進程群組ID。 -
::getpriority
:返回進程、進程群組或用戶的調度優先級。 -
::getsid
:返回進程的會話ID。 -
::groups
:返回此進程的附加組訪問列表中的組ID數組。 -
::groups=
:將附加組訪問列表設置為給定的組ID數組。 -
::initgroups
:初始化附加組訪問列表。 -
::last_status
:返回當前線程中最後執行的子進程的狀態。 -
::maxgroups
:返回附加組訪問列表中允許的最大組ID數量。 -
::maxgroups=
:設置附加組訪問列表中允許的最大組ID數量。 -
::setpgid
:設置進程的進程群組ID。 -
::setpriority
:設置進程、進程群組或用戶的調度優先級。
時間¶ ↑
-
::clock_getres
:返回系統時鐘的分辨率。 -
::clock_gettime
:返回系統時鐘的時間。 -
::times
:返回包含當前進程及其子進程的時間的Process::Tms
對象。
常數
- CLOCK_BOOTTIME
- CLOCK_BOOTTIME_ALARM
- CLOCK_MONOTONIC
- CLOCK_MONOTONIC_COARSE
- CLOCK_MONOTONIC_FAST
- CLOCK_MONOTONIC_PRECISE
- CLOCK_MONOTONIC_RAW
- CLOCK_MONOTONIC_RAW_APPROX
- CLOCK_PROCESS_CPUTIME_ID
- CLOCK_PROF
- CLOCK_REALTIME
- CLOCK_REALTIME_ALARM
- CLOCK_REALTIME_COARSE
- CLOCK_REALTIME_FAST
- CLOCK_REALTIME_PRECISE
- CLOCK_SECOND
- CLOCK_TAI
- CLOCK_THREAD_CPUTIME_ID
- CLOCK_UPTIME
- CLOCK_UPTIME_FAST
- CLOCK_UPTIME_PRECISE
- CLOCK_UPTIME_RAW
- CLOCK_UPTIME_RAW_APPROX
- CLOCK_VIRTUAL
- PRIO_PGRP
- PRIO_PROCESS
- PRIO_USER
- RLIMIT_AS
進程的虛擬內存(地址空間)的最大大小(以字節為單位)。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_CORE
核心文件的最大大小。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_CPU
CPU時間限制,以秒為單位。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_DATA
進程數據段的最大大小。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_FSIZE
進程可以創建的文件的最大大小。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_MEMLOCK
可以鎖定到RAM中的內存字節的最大數量。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_MSGQUEUE
指定了為調用進程的真實用戶ID分配的 POSIX 消息隊列的字節數限制。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_NICE
指定了進程的 nice 值可提高到的上限。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_NOFILE
指定了此進程可以打開的最大文件描述符號碼加一。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_NPROC
調用進程的真實用戶ID可以創建的最大進程數。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_NPTS
調用進程的真實用戶ID可以創建的最大虛擬終端數。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_RSS
指定了進程常駐集的限制(以頁為單位)。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_RTPRIO
指定了可為此進程設置的實時優先級上限。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_RTTIME
指定了此進程在實時調度策略下安排的CPU時間的限制。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_SBSIZE
套接字緩衝區的最大大小。
- RLIMIT_SIGPENDING
指定了為調用進程的真實用戶ID排隊的信號數的限制。
詳情參見系統 getrlimit(2) 手冊。
- RLIMIT_STACK
堆棧的最大大小,以字節為單位。
詳情參見系統 getrlimit(2) 手冊。
- RLIM_INFINITY
- RLIM_SAVED_CUR
- RLIM_SAVED_MAX
- WNOHANG
參見
Process.wait
- WUNTRACED
參見
Process.wait
公共類方法
fork 的內部API。請勿直接調用此方法。目前,通過 Kernel#fork
、Process.fork
和 IO.popen
以 "-"
參數調用此方法。
此方法不適用於常規代碼,而適用於應用程序監控庫。您可以在 fork 事件之前和之後添加自定義代碼,方法是覆蓋此方法。
注意:可能會使用 fork(2) 實現 Process.daemon
,但不會通過此方法進行。因此,根據您鉤入此方法的原因,您可能還想要鉤入該方法。參見 此問題 以獲得更詳細的討論。
VALUE rb_proc__fork(VALUE _obj) { rb_pid_t pid = proc_fork_pid(); return PIDT2NUM(pid); }
立即終止執行,效果上等同於呼叫 Kernel.exit(false)
。
如果給定字串參數 msg
,則在終止之前將其寫入 STDERR;否則,如果引發了異常,則打印其消息和回溯。
static VALUE f_abort(int c, const VALUE *a, VALUE _) { rb_f_abort(c, a); UNREACHABLE_RETURN(Qnil); }
返回正在執行的腳本的名稱。該值不受將新值分配給 $0 的影響。
此方法首次出現在 Ruby 2.1 中,用作全局變量自由方式以獲取腳本名稱。
static VALUE proc_argv0(VALUE process) { return rb_orig_progname; }
返回由 POSIX 函数 clock_getres() 確定的時鐘分辨率
Process.clock_getres(:CLOCK_REALTIME) # => 1.0e-09
參見 Process.clock_gettime
以獲取 clock_id
和 unit
的值。
範例
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_microsecond) # => 0.001 Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_millisecond) # => 1.0e-06 Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_second) # => 1.0e-09 Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :microsecond) # => 0 Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :millisecond) # => 0 Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :nanosecond) # => 1 Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :second) # => 0
除了 Process.clock_gettime
中支持的 unit
值外,此方法還支持 :hertz
,即每秒鐘的時鐘滴答數(與 :float_second
的倒數)的整數。
Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz) # => 100.0 Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :float_second) # => 0.01
精度:請注意,由於底層錯誤,返回的分辨率在某些平台上可能不準確。對於包括 Linux、macOS、BSD 或 AIX 平台上的 ARM 處理器或虛擬化中使用的各種時鐘(例如 :CLOCK_MONOTONIC
和 :CLOCK_MONOTONIC_RAW
),已報告了不準確的解析度。
static VALUE rb_clock_getres(int argc, VALUE *argv, VALUE _) { int ret; struct timetick tt; timetick_int_t numerators[2]; timetick_int_t denominators[2]; int num_numerators = 0; int num_denominators = 0; #ifdef HAVE_CLOCK_GETRES clockid_t c; #endif VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil; VALUE clk_id = argv[0]; if (SYMBOL_P(clk_id)) { #ifdef CLOCK_REALTIME if (clk_id == RUBY_CLOCK_REALTIME) { c = CLOCK_REALTIME; goto getres; } #endif #ifdef CLOCK_MONOTONIC if (clk_id == RUBY_CLOCK_MONOTONIC) { c = CLOCK_MONOTONIC; goto getres; } #endif #ifdef CLOCK_PROCESS_CPUTIME_ID if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) { c = CLOCK_PROCESS_CPUTIME_ID; goto getres; } #endif #ifdef CLOCK_THREAD_CPUTIME_ID if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) { c = CLOCK_THREAD_CPUTIME_ID; goto getres; } #endif #ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) { tt.giga_count = 0; tt.count = 1000; denominators[num_denominators++] = 1000000000; goto success; } #endif #ifdef RUBY_TIME_BASED_CLOCK_REALTIME if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) { tt.giga_count = 1; tt.count = 0; denominators[num_denominators++] = 1000000000; goto success; } #endif #ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) { tt.count = 1; tt.giga_count = 0; denominators[num_denominators++] = get_clk_tck(); goto success; } #endif #ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) { tt.giga_count = 0; tt.count = 1000; denominators[num_denominators++] = 1000000000; goto success; } #endif #ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) { tt.count = 1; tt.giga_count = 0; denominators[num_denominators++] = get_clk_tck(); goto success; } #endif #ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) { tt.count = 1; tt.giga_count = 0; denominators[num_denominators++] = CLOCKS_PER_SEC; goto success; } #endif #ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) { const mach_timebase_info_data_t *info = get_mach_timebase_info(); tt.count = 1; tt.giga_count = 0; numerators[num_numerators++] = info->numer; denominators[num_denominators++] = info->denom; denominators[num_denominators++] = 1000000000; goto success; } #endif } else if (NUMERIC_CLOCKID) { #if defined(HAVE_CLOCK_GETRES) struct timespec ts; c = NUM2CLOCKID(clk_id); getres: ret = clock_getres(c, &ts); if (ret == -1) clock_failed("getres", errno, clk_id); tt.count = (int32_t)ts.tv_nsec; tt.giga_count = ts.tv_sec; denominators[num_denominators++] = 1000000000; goto success; #endif } else { rb_unexpected_type(clk_id, T_SYMBOL); } clock_failed("getres", EINVAL, clk_id); success: if (unit == ID2SYM(id_hertz)) { return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators); } else { return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit); } }
返回由 POSIX 函数 clock_gettime() 確定的時鐘時間
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID) # => 198.650379677
參數 clock_id
應為指定要返回其時間的時鐘的符號或常量;請參見下文。
可選參數 unit
應為指定返回的時鐘時間中使用的單位的符號;請參見下文。
參數 clock_id
參數 clock_id
指定要返回其時間的時鐘;它可以是像 Process::CLOCK_REALTIME
這樣的常量,或者是像 :CLOCK_REALTIME
這樣的符號簡寫。
支援的時鐘取決於底層作業系統;此方法支援指定平台上的以下時鐘(如果使用不受支援的時鐘呼叫此方法,則引發 Errno::EINVAL)
-
:CLOCK_BOOTTIME
: Linux 2.6.39。 -
:CLOCK_BOOTTIME_ALARM
: Linux 3.0。 -
:CLOCK_MONOTONIC
: SUSv3 到 4,Linux 2.5.63,FreeBSD 3.0,NetBSD 2.0,OpenBSD 3.4,macOS 10.12,Windows-2000。 -
:CLOCK_MONOTONIC_COARSE
: Linux 2.6.32。 -
:CLOCK_MONOTONIC_FAST
: FreeBSD 8.1。 -
:CLOCK_MONOTONIC_PRECISE
: FreeBSD 8.1。 -
:CLOCK_MONOTONIC_RAW
: Linux 2.6.28,macOS 10.12。 -
:CLOCK_MONOTONIC_RAW_APPROX
: macOS 10.12。 -
:CLOCK_PROCESS_CPUTIME_ID
: SUSv3 到 4,Linux 2.5.63,FreeBSD 9.3,OpenBSD 5.4,macOS 10.12。 -
:CLOCK_PROF
: FreeBSD 3.0,OpenBSD 2.1。 -
:CLOCK_REALTIME
: SUSv2 到 4,Linux 2.5.63,FreeBSD 3.0,NetBSD 2.0,OpenBSD 2.1,macOS 10.12,Windows-8/Server-2012。建議使用 +:CLOCK_REALTIME: 的Time.now
。 -
:CLOCK_REALTIME_ALARM
: Linux 3.0。 -
:CLOCK_REALTIME_COARSE
: Linux 2.6.32。 -
:CLOCK_REALTIME_FAST
: FreeBSD 8.1。 -
:CLOCK_REALTIME_PRECISE
: FreeBSD 8.1。 -
:CLOCK_SECOND
: FreeBSD 8.1。 -
:CLOCK_TAI
: Linux 3.10。 -
:CLOCK_THREAD_CPUTIME_ID
: SUSv3 到 4,Linux 2.5.63,FreeBSD 7.1,OpenBSD 5.4,macOS 10.12。 -
:CLOCK_UPTIME
: FreeBSD 7.0,OpenBSD 5.5。 -
:CLOCK_UPTIME_FAST
: FreeBSD 8.1。 -
:CLOCK_UPTIME_PRECISE
: FreeBSD 8.1。 -
:CLOCK_UPTIME_RAW
: macOS 10.12。 -
:CLOCK_UPTIME_RAW_APPROX
: macOS 10.12。 -
:CLOCK_VIRTUAL
: FreeBSD 3.0,OpenBSD 2.1。
注意,SUS 代表 Single Unix Specification。SUS 包含 POSIX,而 clock_gettime
在 POSIX 部分中定義。SUS 將 :CLOCK_REALTIME
定義為強制性,但 :CLOCK_MONOTONIC
、:CLOCK_PROCESS_CPUTIME_ID
和 :CLOCK_THREAD_CPUTIME_ID
為可選。
當給定的 clock_id
不直接支援時,會使用某些模擬。
-
:CLOCK_REALTIME
的模擬-
:GETTIMEOFDAY_BASED_CLOCK_REALTIME
: 使用 SUS 定義的 gettimeofday()(在 SUSv4 中已棄用)。解析度為 1 微秒。 -
:TIME_BASED_CLOCK_REALTIME
: 使用 ISO C 定義的 time()。解析度為 1 秒。
-
-
:CLOCK_MONOTONIC
的模擬-
:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
: 使用 Darwin 上可用的 mach_absolute_time()。解析度取決於 CPU。 -
:TIMES_BASED_CLOCK_MONOTONIC
: 使用 POSIX 定義的 times() 的結果值,因此成功完成後,times() 將返回自過去某一點以來的經過的真實時間,以時鐘滴答數表示(例如,系統啟動時間)。
例如,GNU/Linux 返回基於 jiffies 的值並且是單調的。但是,4.4BSD 使用 gettimeofday(),並且不是單調的。(FreeBSD 則使用
:CLOCK_MONOTONIC
。)解析度為時鐘滴答數。使用“getconf CLK_TCK”命令顯示每秒時鐘滴答數。(時鐘每秒滴答數由舊系統中的 HZ 宏定義。)如果它是 100,且 clock_t 是 32 位整數類型,則解析度為 10 毫秒,並且不能表示超過
-
-
:CLOCK_PROCESS_CPUTIME_ID
的模擬-
:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
:使用由SUS定義的getrusage()。getrusage() 與RUSAGE_SELF一起使用,僅獲取呼叫進程的時間(不包括子進程的時間)。結果是用戶時間(ru_utime)和系統時間(ru_stime)的總和。解析度為1微秒。 -
:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
:使用由POSIX定義的times()。結果是用戶時間(tms_utime)和系統時間(tms_stime)的總和。忽略tms_cutime和tms_cstime以排除子進程的時間。解析度為時鐘滴答。 "getconf CLK_TCK" 命令顯示每秒的時鐘滴答數。(時鐘滴答數每秒由較舊的系統中的HZ宏定義。)如果是100,解析度為10毫秒。 -
:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
:使用由ISO C定義的clock()。解析度為1/CLOCKS_PER_SEC
。CLOCKS_PER_SEC
是由time.h定義的C級宏。SUS將定義為1000000;其他系統可能會以不同的方式定義它。如果 是1000000(如在SUS中),則解析度為1微秒。如果 是1000000且clock_t是32位整數類型,則不能表示超過72分鐘。
-
參數unit
可選參數unit
(默認:float_second
)指定返回值的單位。
-
:float_microsecond
:微秒數以浮點數表示。 -
:float_millisecond
:毫秒數以浮點數表示。 -
:float_second
:秒數以浮點數表示。 -
:microsecond
:微秒數以整數表示。 -
:millisecond
:毫秒數以整數表示。 -
:nanosecond
:納秒數以整數表示。 -
::second
:秒數以整數表示。
範例
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_microsecond) # => 203605054.825 Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_millisecond) # => 203643.696848 Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_second) # => 203.762181929 Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :microsecond) # => 204123212 Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :millisecond) # => 204298 Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :nanosecond) # => 204602286036 Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :second) # => 204
底層函數clock_gettime
()返回一定數量的納秒。Float
對象(IEEE 754雙精度)不足以表示unit
設置為:nanosecond
。
返回值的原點(時間零點)取決於系統,例如系統啟動時間、進程啟動時間、紀元等。
1970-01-01 00:00:00 UTC
;某些系統計算閏秒,而其他系統則不計算,因此結果可能因系統而異。
static VALUE rb_clock_gettime(int argc, VALUE *argv, VALUE _) { int ret; struct timetick tt; timetick_int_t numerators[2]; timetick_int_t denominators[2]; int num_numerators = 0; int num_denominators = 0; VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil; VALUE clk_id = argv[0]; #ifdef HAVE_CLOCK_GETTIME clockid_t c; #endif if (SYMBOL_P(clk_id)) { #ifdef CLOCK_REALTIME if (clk_id == RUBY_CLOCK_REALTIME) { c = CLOCK_REALTIME; goto gettime; } #endif #ifdef CLOCK_MONOTONIC if (clk_id == RUBY_CLOCK_MONOTONIC) { c = CLOCK_MONOTONIC; goto gettime; } #endif #ifdef CLOCK_PROCESS_CPUTIME_ID if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) { c = CLOCK_PROCESS_CPUTIME_ID; goto gettime; } #endif #ifdef CLOCK_THREAD_CPUTIME_ID if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) { c = CLOCK_THREAD_CPUTIME_ID; goto gettime; } #endif /* * Non-clock_gettime clocks are provided by symbol clk_id. */ #ifdef HAVE_GETTIMEOFDAY /* * GETTIMEOFDAY_BASED_CLOCK_REALTIME is used for * CLOCK_REALTIME if clock_gettime is not available. */ #define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME) if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) { struct timeval tv; ret = gettimeofday(&tv, 0); if (ret != 0) rb_sys_fail("gettimeofday"); tt.giga_count = tv.tv_sec; tt.count = (int32_t)tv.tv_usec * 1000; denominators[num_denominators++] = 1000000000; goto success; } #endif #define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME) if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) { time_t t; t = time(NULL); if (t == (time_t)-1) rb_sys_fail("time"); tt.giga_count = t; tt.count = 0; denominators[num_denominators++] = 1000000000; goto success; } #ifdef HAVE_TIMES #define RUBY_TIMES_BASED_CLOCK_MONOTONIC \ ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC) if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) { struct tms buf; clock_t c; unsigned_clock_t uc; c = times(&buf); if (c == (clock_t)-1) rb_sys_fail("times"); uc = (unsigned_clock_t)c; tt.count = (int32_t)(uc % 1000000000); tt.giga_count = (uc / 1000000000); denominators[num_denominators++] = get_clk_tck(); goto success; } #endif #ifdef RUSAGE_SELF #define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \ ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) { struct rusage usage; int32_t usec; ret = getrusage(RUSAGE_SELF, &usage); if (ret != 0) rb_sys_fail("getrusage"); tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec; usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec); if (1000000 <= usec) { tt.giga_count++; usec -= 1000000; } tt.count = usec * 1000; denominators[num_denominators++] = 1000000000; goto success; } #endif #ifdef HAVE_TIMES #define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \ ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) { struct tms buf; unsigned_clock_t utime, stime; if (times(&buf) == (clock_t)-1) rb_sys_fail("times"); utime = (unsigned_clock_t)buf.tms_utime; stime = (unsigned_clock_t)buf.tms_stime; tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000)); tt.giga_count = (utime / 1000000000) + (stime / 1000000000); if (1000000000 <= tt.count) { tt.count -= 1000000000; tt.giga_count++; } denominators[num_denominators++] = get_clk_tck(); goto success; } #endif #define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \ ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) { clock_t c; unsigned_clock_t uc; errno = 0; c = clock(); if (c == (clock_t)-1) rb_sys_fail("clock"); uc = (unsigned_clock_t)c; tt.count = (int32_t)(uc % 1000000000); tt.giga_count = uc / 1000000000; denominators[num_denominators++] = CLOCKS_PER_SEC; goto success; } #ifdef __APPLE__ if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) { const mach_timebase_info_data_t *info = get_mach_timebase_info(); uint64_t t = mach_absolute_time(); tt.count = (int32_t)(t % 1000000000); tt.giga_count = t / 1000000000; numerators[num_numerators++] = info->numer; denominators[num_denominators++] = info->denom; denominators[num_denominators++] = 1000000000; goto success; } #endif } else if (NUMERIC_CLOCKID) { #if defined(HAVE_CLOCK_GETTIME) struct timespec ts; c = NUM2CLOCKID(clk_id); gettime: ret = clock_gettime(c, &ts); if (ret == -1) clock_failed("gettime", errno, clk_id); tt.count = (int32_t)ts.tv_nsec; tt.giga_count = ts.tv_sec; denominators[num_denominators++] = 1000000000; goto success; #endif } else { rb_unexpected_type(clk_id, T_SYMBOL); } clock_failed("gettime", EINVAL, clk_id); success: return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit); }
將當前進程與其控制終端分離,並將其作為系統守護進程在後台運行;返回零。
默認情況下
-
將當前工作目錄更改為根目錄。
-
將 $stdin、$stdout 和 $stderr 重定向到空設備。
如果可選參數 nochdir
為 true
,則不更改當前工作目錄。
如果可選參數 noclose
為 true
,則不重定向 $stdin、$stdout 或 $stderr。
static VALUE proc_daemon(int argc, VALUE *argv, VALUE _) { int n, nochdir = FALSE, noclose = FALSE; switch (rb_check_arity(argc, 0, 2)) { case 2: noclose = TO_BOOL(argv[1], "noclose"); case 1: nochdir = TO_BOOL(argv[0], "nochdir"); } prefork(); n = rb_daemon(nochdir, noclose); if (n < 0) rb_sys_fail("daemon"); return INT2FIX(n); }
避免子進程成為殭屍進程的可能性。通過設置一個獨立的 Ruby 线程,其唯一工作是在終止時收集進程 pid 的狀態,Process.detach
避免了這一點。
此方法僅在父進程永遠不會等待子進程時才需要。
此示例未收集第二個子進程;該進程將出現為進程狀態 (ps
) 輸出中的殭屍
pid = Process.spawn('ruby', '-e', 'exit 13') # => 312691 sleep(1) # Find zombies. system("ps -ho pid,state -p #{pid}")
輸出
312716 Z
此示例也未收集第二個子進程,但它分離了進程,使其不會成為殭屍
pid = Process.spawn('ruby', '-e', 'exit 13') # => 313213 thread = Process.detach(pid) sleep(1) # => #<Process::Waiter:0x00007f038f48b838 run> system("ps -ho pid,state -p #{pid}") # Finds no zombies.
等待的線程可以返回分離的子進程的 pid
thread.join.pid # => 313262
static VALUE proc_detach(VALUE obj, VALUE pid) { return rb_detach_process(NUM2PIDT(pid)); }
返回當前進程的有效組 ID
Process.egid # => 500
不適用於所有平台。
static VALUE proc_getegid(VALUE obj) { rb_gid_t egid = getegid(); return GIDT2NUM(egid); }
設置當前進程的有效組 ID。
不適用於所有平台。
static VALUE proc_setegid(VALUE obj, VALUE egid) { #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) rb_gid_t gid; #endif check_gid_switch(); #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) gid = OBJ2GID(egid); #endif #if defined(HAVE_SETRESGID) if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0); #elif defined HAVE_SETREGID if (setregid(-1, gid) < 0) rb_sys_fail(0); #elif defined HAVE_SETEGID if (setegid(gid) < 0) rb_sys_fail(0); #elif defined HAVE_SETGID if (gid == getgid()) { if (setgid(gid) < 0) rb_sys_fail(0); } else { rb_notimplement(); } #else rb_notimplement(); #endif return egid; }
返回當前進程的有效用戶 ID。
Process.euid # => 501
static VALUE proc_geteuid(VALUE obj) { rb_uid_t euid = geteuid(); return UIDT2NUM(euid); }
設置當前進程的有效用戶 ID。
不適用於所有平台。
static VALUE proc_seteuid_m(VALUE mod, VALUE euid) { check_uid_switch(); proc_seteuid(OBJ2UID(euid)); return euid; }
通過執行以下操作之一來替換當前進程
-
將字符串
command_line
傳遞給 shell。 -
調用
exe_path
中的可執行文件。
如果使用不受信任的輸入調用此方法,則可能存在潛在的安全漏洞;請參見命令注入。
新進程是使用exec 系統調用創建的;它可能從調用程序繼承一些環境(可能包括打開的文件描述符)。
參數 env
,如果提供,是一個影響新進程的 ENV
的哈希;請參閱 執行環境。
參數 options
是一個用於新進程的選項哈希;請參閱 執行選項。
第一個必需的參數是以下之一
-
command_line
如果它是一個字符串,並且如果它以 shell 保留字開頭或特殊內置,或者如果它包含一個或多個元字符。 -
否則為
exe_path
。
參數 command_line
字符串參數 command_line
是要傳遞給 shell 的命令行;它必須以 shell 保留字開頭,以特殊內建開頭,或包含元字符
exec('if true; then echo "Foo"; fi') # Shell reserved word. exec('echo') # Built-in. exec('date > date.tmp') # Contains meta character.
命令行還可以包含用於該命令的參數和選項
exec('echo "Foo"')
輸出
Foo
有關 shell 的詳細信息,請參見 Execution Shell。
如果新進程無法執行,則引發異常。
參數 exe_path
參數 exe_path
是以下之一
-
要調用的可執行文件的字符串路徑。
-
包含可執行文件的路徑和要用作執行進程名稱的字符串的2元素陣列。
示例
exec('/usr/bin/date')
輸出
Sat Aug 26 09:38:00 AM CDT 2023
Ruby 直接調用可執行文件,不使用 shell 或 shell 展開。
exec('doesnt_exist') # Raises Errno::ENOENT
如果給定一個或多個 args
,則每個都是要傳遞給可執行文件的參數或選項
exec('echo', 'C*') exec('echo', 'hello', 'world')
輸出
C* hello world
如果新進程無法執行,則引發異常。
static VALUE f_exec(int c, const VALUE *a, VALUE _) { rb_f_exec(c, a); UNREACHABLE_RETURN(Qnil); }
通過引發 SystemExit
來啟動 Ruby 腳本的終止;異常可能會被捕獲。將退出狀態 status
返回給底層操作系統。
對於參數 status
,值 true
和 false
分別表示成功和失敗;整數值的含義是系統相依的。
示例
begin exit puts 'Never get here.' rescue SystemExit puts 'Rescued a SystemExit exception.' end puts 'After begin block.'
輸出
Rescued a SystemExit exception. After begin block.
在最終終止之前,Ruby 執行任何結束時程序(參見 Kernel::at_exit)和任何對象終結者(參見 ObjectSpace::define_finalizer
)。
示例
at_exit { puts 'In at_exit function.' } ObjectSpace.define_finalizer('string', proc { puts 'In finalizer.' }) exit
輸出
In at_exit function. In finalizer.
static VALUE f_exit(int c, const VALUE *a, VALUE _) { rb_f_exit(c, a); UNREACHABLE_RETURN(Qnil); }
立即退出進程;不調用退出處理程序。將退出狀態 status
返回給底層操作系統。
Process.exit!(true)
對於參數 status
,值 true
和 false
分別表示成功和失敗;整數值的含義是系統相依的。
static VALUE rb_f_exit_bang(int argc, VALUE *argv, VALUE obj) { int istatus; if (rb_check_arity(argc, 0, 1) == 1) { istatus = exit_status_code(argv[0]); } else { istatus = EXIT_FAILURE; } _exit(istatus); UNREACHABLE_RETURN(Qnil); }
創建一個子進程。
給定一個塊時,在子進程中運行該塊;在塊退出時,子進程以零狀態終止
puts "Before the fork: #{Process.pid}" fork do puts "In the child process: #{Process.pid}" end # => 382141 puts "After the fork: #{Process.pid}"
輸出
Before the fork: 420496 After the fork: 420496 In the child process: 420520
未給定塊時,fork
調用返回兩次
-
一次在父進程中,返回子進程的 pid。
-
一次在子進程中,返回
nil
。
示例
puts "This is the first line before the fork (pid #{Process.pid})" puts fork puts "This is the second line after the fork (pid #{Process.pid})"
輸出
This is the first line before the fork (pid 420199) 420223 This is the second line after the fork (pid 420199) This is the second line after the fork (pid 420223)
在任一情況下,子進程可以使用 Kernel.exit!
退出,以避免調用 Kernel#at_exit
。
為了避免殭屍進程,父進程應該調用以下方法之一
-
Process.wait
,以收集其子進程的終止狀態。 -
Process.detach
,以表明對其狀態不感興趣。
調用fork
的線程是創建的子進程中唯一的線程;fork
不會複製其他線程。
請注意,方法fork
在某些平台上可用,但在其他平台上則不可用
Process.respond_to?(:fork) # => true # Would be false on some.
如果不可用,可以使用::spawn
代替fork
。
static VALUE rb_f_fork(VALUE obj) { rb_pid_t pid; pid = rb_call_proc__fork(); if (pid == 0) { if (rb_block_given_p()) { int status; rb_protect(rb_yield, Qundef, &status); ruby_stop(status); } return Qnil; } return PIDT2NUM(pid); }
Returns the process group ID for the given process ID +pid+: Process.getpgid(Process.ppid) # => 25527
不適用於所有平台。
static VALUE proc_getpgid(VALUE obj, VALUE pid) { rb_pid_t i; i = getpgid(NUM2PIDT(pid)); if (i < 0) rb_sys_fail(0); return PIDT2NUM(i); }
返回當前進程的進程組 ID
Process.getpgid(0) # => 25527 Process.getpgrp # => 25527
static VALUE proc_getpgrp(VALUE _) { rb_pid_t pgrp; #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID) pgrp = getpgrp(); if (pgrp < 0) rb_sys_fail(0); return PIDT2NUM(pgrp); #else /* defined(HAVE_GETPGID) */ pgrp = getpgid(0); if (pgrp < 0) rb_sys_fail(0); return PIDT2NUM(pgrp); #endif }
返回指定進程、進程組或用戶的調度優先級。
參數kind
之一是
-
Process::PRIO_PROCESS
:返回進程的優先級。 -
Process::PRIO_PGRP
:返回進程組的優先級。 -
Process::PRIO_USER
:返回用戶的優先級。
參數id
是進程、進程組或用戶的 ID;指定kind
時,零表示當前 ID。
範例
Process.getpriority(Process::PRIO_USER, 0) # => 19 Process.getpriority(Process::PRIO_PROCESS, 0) # => 19
不適用於所有平台。
static VALUE proc_getpriority(VALUE obj, VALUE which, VALUE who) { int prio, iwhich, iwho; iwhich = NUM2INT(which); iwho = NUM2INT(who); errno = 0; prio = getpriority(iwhich, iwho); if (errno) rb_sys_fail(0); return INT2FIX(prio); }
返回給定resource
的當前(軟)限制和最大(硬)限制的2元素數組。
參數resource
指定要返回其限制的資源;參見Process.setrlimit
。
返回值cur_limit
和max_limit
都是整數;參見Process.setrlimit
。
示例
Process.getrlimit(:CORE) # => [0, 18446744073709551615]
不適用於所有平台。
static VALUE proc_getrlimit(VALUE obj, VALUE resource) { struct rlimit rlim; if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) { rb_sys_fail("getrlimit"); } return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max)); }
返回給定進程 ID pid
的會話 ID,如果未給出則返回當前進程的會話 ID
Process.getsid # => 27422 Process.getsid(0) # => 27422 Process.getsid(Process.pid()) # => 27422
不適用於所有平台。
static VALUE proc_getsid(int argc, VALUE *argv, VALUE _) { rb_pid_t sid; rb_pid_t pid = 0; if (rb_check_arity(argc, 0, 1) == 1 && !NIL_P(argv[0])) pid = NUM2PIDT(argv[0]); sid = getsid(pid); if (sid < 0) rb_sys_fail(0); return PIDT2NUM(sid); }
返回當前進程的(真實)組 ID
Process.gid # => 1000
static VALUE proc_getgid(VALUE obj) { rb_gid_t gid = getgid(); return GIDT2NUM(gid); }
將當前進程的組 ID 設置為new_gid
Process.gid = 1000 # => 1000
static VALUE proc_setgid(VALUE obj, VALUE id) { rb_gid_t gid; check_gid_switch(); gid = OBJ2GID(id); #if defined(HAVE_SETRESGID) if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0); #elif defined HAVE_SETREGID if (setregid(gid, -1) < 0) rb_sys_fail(0); #elif defined HAVE_SETRGID if (setrgid(gid) < 0) rb_sys_fail(0); #elif defined HAVE_SETGID { if (getegid() == gid) { if (setgid(gid) < 0) rb_sys_fail(0); } else { rb_notimplement(); } } #endif return GIDT2NUM(gid); }
返回當前進程的補充組訪問列表中的組 ID 數組
Process.groups # => [4, 24, 27, 30, 46, 122, 135, 136, 1000]
返回的數組的這些屬性是系統相關的
-
陣列是否已排序,以及排序方式。
-
陣列是否包含有效的群組 ID。
-
陣列是否包含重複的群組 ID。
-
陣列大小是否超過
Process.maxgroups
的值。
使用此呼叫可獲得排序且唯一的陣列
Process.groups.uniq.sort
static VALUE proc_getgroups(VALUE obj) { VALUE ary, tmp; int i, ngroups; rb_gid_t *groups; ngroups = getgroups(0, NULL); if (ngroups == -1) rb_sys_fail(0); groups = ALLOCV_N(rb_gid_t, tmp, ngroups); ngroups = getgroups(ngroups, groups); if (ngroups == -1) rb_sys_fail(0); ary = rb_ary_new(); for (i = 0; i < ngroups; i++) rb_ary_push(ary, GIDT2NUM(groups[i])); ALLOCV_END(tmp); return ary; }
將補充群組存取清單設置為給定的群組 ID 陣列。
Process.groups # => [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27] Process.groups = [27, 6, 10, 11] # => [27, 6, 10, 11] Process.groups # => [27, 6, 10, 11]
static VALUE proc_setgroups(VALUE obj, VALUE ary) { int ngroups, i; rb_gid_t *groups; VALUE tmp; PREPARE_GETGRNAM; Check_Type(ary, T_ARRAY); ngroups = RARRAY_LENINT(ary); if (ngroups > maxgroups()) rb_raise(rb_eArgError, "too many groups, %d max", maxgroups()); groups = ALLOCV_N(rb_gid_t, tmp, ngroups); for (i = 0; i < ngroups; i++) { VALUE g = RARRAY_AREF(ary, i); groups[i] = OBJ2GID1(g); } FINISH_GETGRNAM; if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */ rb_sys_fail(0); ALLOCV_END(tmp); return proc_getgroups(obj); }
設置補充群組存取清單;新清單包含
-
屬於由
username
指定的使用者所屬的那些群組的群組 ID。 -
群組 ID
gid
。
示例
Process.groups # => [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27] Process.initgroups('me', 30) # => [30, 6, 10, 11] Process.groups # => [30, 6, 10, 11]
不適用於所有平台。
static VALUE proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp) { if (initgroups(StringValueCStr(uname), OBJ2GID(base_grp)) != 0) { rb_sys_fail(0); } return proc_getgroups(obj); }
對每個指定的 ids
進程發送一個信號(必須至少指定一個 ID);返回發送的信號計數。
對於每個給定的 id
,如果 id
是
-
正數,則將信號發送給其進程 ID 為
id
的進程。 -
零,將信號發送給當前進程組中的所有進程。
-
負數,將信號發送給系統相關的一組進程。
引數 signal
指定要發送的信號;引數可以是
-
一個整數信號號:例如,
-29
、0
、29
。 -
一個信號名稱(字符串),帶有或不帶有前導的
'SIG'
,以及帶有或不帶有進一步的前綴減號('-'
):例如-
'SIGPOLL'
. -
'POLL'
, -
'-SIGPOLL'
. -
'-POLL'
.
-
-
一個信號符號,帶有或不帶有前導的
'SIG'
,以及帶有或不帶有進一步的前綴減號('-'
):例如-
:SIGPOLL
. -
:POLL
. -
:'-SIGPOLL'
. -
:'-POLL'
.
-
如果 signal
是
-
一個非負整數,或者不帶前綴
'-'
的信號名稱或符號,則對具有進程 IDid
的每個進程發送信號。 -
一個負整數,或者帶有前綴
'-'
的信號名稱或符號,則對具有群組 IDid
的每個進程組發送信號。
使用方法 Signal.list
來查看 Ruby 在底層平台上支持哪些信號;該方法返回支持的信號的字符串名稱和非負整數值的哈希表。返回的哈希表的大小和內容在不同平台上有很大差異。
另外,信號 0
在判斷進程是否存在時很有用。
示例
pid = fork do Signal.trap('HUP') { puts 'Ouch!'; exit } # ... do some work ... end # ... Process.kill('HUP', pid) Process.wait
輸出
Ouch!
異常
-
如果
signal
是整數但無效,則引發 Errno::EINVAL 或RangeError
。 -
如果
signal
是字符串或符號但無效,則引發ArgumentError
。 -
如果其中一個
ids
無效,則引發 Errno::ESRCH 或RangeError
。 -
如果需要的權限未生效,則引發 Errno::EPERM。
在最後兩種情況下,信號可能已發送到某些進程。
static VALUE proc_rb_f_kill(int c, const VALUE *v, VALUE _) { return rb_f_kill(c, v); }
返回表示當前線程中最近退出的子進程的 Process::Status
對象,如果沒有則返回 nil
。
Process.spawn('ruby', '-e', 'exit 13') Process.wait Process.last_status # => #<Process::Status: pid 14396 exit 13> Process.spawn('ruby', '-e', 'exit 14') Process.wait Process.last_status # => #<Process::Status: pid 4692 exit 14> Process.spawn('ruby', '-e', 'exit 15') # 'exit 15' has not been reaped by #wait. Process.last_status # => #<Process::Status: pid 4692 exit 14> Process.wait Process.last_status # => #<Process::Status: pid 1380 exit 15>
static VALUE proc_s_last_status(VALUE mod) { return rb_last_status_get(); }
返回輔助組訪問列表中允許的最大組 ID 數。
Process.maxgroups # => 32
static VALUE proc_getmaxgroups(VALUE obj) { return INT2FIX(maxgroups()); }
設置輔助組訪問列表中允許的最大組 ID 數。
static VALUE proc_setmaxgroups(VALUE obj, VALUE val) { int ngroups = FIX2INT(val); int ngroups_max = get_sc_ngroups_max(); if (ngroups <= 0) rb_raise(rb_eArgError, "maxgroups %d should be positive", ngroups); if (ngroups > RB_MAX_GROUPS) ngroups = RB_MAX_GROUPS; if (ngroups_max > 0 && ngroups > ngroups_max) ngroups = ngroups_max; _maxgroups = ngroups; return INT2FIX(_maxgroups); }
返回當前進程的進程 ID。
Process.pid # => 15668
static VALUE proc_get_pid(VALUE _) { return get_pid(); }
返回當前進程的父進程的進程 ID。
puts "Pid is #{Process.pid}." fork { puts "Parent pid is #{Process.ppid}." }
輸出
Pid is 271290. Parent pid is 271290.
在某些平台上可能無法返回可靠的值。
static VALUE proc_get_ppid(VALUE _) { return get_ppid(); }
將由進程 ID pid
指定的進程的進程組 ID 設置為 pgid
。
不適用於所有平台。
static VALUE proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp) { rb_pid_t ipid, ipgrp; ipid = NUM2PIDT(pid); ipgrp = NUM2PIDT(pgrp); if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0); return INT2FIX(0); }
等效於 setpgid(0, 0)
。
不適用於所有平台。
static VALUE proc_setpgrp(VALUE _) { /* check for posix setpgid() first; this matches the posix */ /* getpgrp() above. It appears that configure will set SETPGRP_VOID */ /* even though setpgrp(0,0) would be preferred. The posix call avoids */ /* this confusion. */ #ifdef HAVE_SETPGID if (setpgid(0,0) < 0) rb_sys_fail(0); #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID) if (setpgrp() < 0) rb_sys_fail(0); #endif return INT2FIX(0); }
範例
Process.setpriority(Process::PRIO_USER, 0, 19) # => 0 Process.setpriority(Process::PRIO_PROCESS, 0, 19) # => 0 Process.getpriority(Process::PRIO_USER, 0) # => 19 Process.getpriority(Process::PRIO_PROCESS, 0) # => 19
不適用於所有平台。
static VALUE proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio) { int iwhich, iwho, iprio; iwhich = NUM2INT(which); iwho = NUM2INT(who); iprio = NUM2INT(prio); if (setpriority(iwhich, iwho, iprio) < 0) rb_sys_fail(0); return INT2FIX(0); }
設置顯示在 ps(1) 命令上的進程標題。在所有平台上都不一定有效。無論結果如何,都不會引發異常,即使平台不支持此功能也不會引發 NotImplementedError
。
調用此方法不會影響 $0 的值。
Process.setproctitle('myapp: worker #%d' % worker_id)
此方法首次出現於 Ruby 2.1,是一種全局變量自由更改進程標題的手段。
static VALUE proc_setproctitle(VALUE process, VALUE title) { return ruby_setproctitle(title); }
為給定的resource
設置當前進程的限制為cur_limit
(軟限制)和max_limit
(硬限制);返回nil
。
參數resource
指定要設置限制的資源;該參數可以作為符號、字符串或以Process::RLIMIT_
開頭的常數給出(例如,:CORE
,'CORE'
或Process::RLIMIT_CORE
)。
可用且支持的資源取決於系統,可能包括(此處以符號表示)
-
:AS
:總可用內存(字節)(SUSv3,NetBSD,FreeBSD,OpenBSD除4.4BSD-Lite外)。 -
:CORE
:核心大小(字節)(SUSv3)。 -
:CPU
:CPU時間(秒)(SUSv3)。 -
:DATA
:數據段(字節)(SUSv3)。 -
:FSIZE
:文件大小(字節)(SUSv3)。 -
:MEMLOCK
:mlock(2)的總大小(字節)(4.4BSD,GNU/Linux)。 -
:MSGQUEUE
:POSIX消息隊列的分配(字節)(GNU/Linux)。 -
:NICE
:進程的nice(2)值的上限(數字)(GNU/Linux)。 -
:NOFILE
:文件描述符(數字)(SUSv3)。 -
:NPROC
:用戶的進程數(數字)(4.4BSD,GNU/Linux)。 -
:NPTS
:虛擬終端數量(數字)(FreeBSD)。 -
:RSS
:居住內存大小(字節)(4.2BSD,GNU/Linux)。 -
:RTPRIO
:進程的實時優先級的上限(數字)(GNU/Linux)。 -
:RTTIME
:實時進程的CPU時間(微秒)(GNU/Linux)。 -
:SBSIZE
:所有套接字緩衝區(字節)(NetBSD,FreeBSD)。 -
:SIGPENDING
:允許的排隊信號數量(信號)(GNU/Linux)。 -
:STACK
:堆棧大小(字節)(SUSv3)。
參數cur_limit
和max_limit
可以是
-
整數(
max_limit
不應小於cur_limit
)。 -
Symbol
:SAVED_MAX
,字符串'SAVED_MAX'
,或常數Process::RLIM_SAVED_MAX
:保存的最大限制。 -
Symbol
:SAVED_CUR
,字符串'SAVED_CUR'
,或常數Process::RLIM_SAVED_CUR
:保存的當前限制。 -
Symbol
:INFINITY
,字符串'INFINITY'
,或常數Process::RLIM_INFINITY
:無資源限制。
此示例將核心大小的軟限制提高到硬限制,以嘗試生成核心轉儲。
Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
不適用於所有平台。
static VALUE proc_setrlimit(int argc, VALUE *argv, VALUE obj) { VALUE resource, rlim_cur, rlim_max; struct rlimit rlim; rb_check_arity(argc, 2, 3); resource = argv[0]; rlim_cur = argv[1]; if (argc < 3 || NIL_P(rlim_max = argv[2])) rlim_max = rlim_cur; rlim.rlim_cur = rlimit_resource_value(rlim_cur); rlim.rlim_max = rlimit_resource_value(rlim_max); if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) { rb_sys_fail("setrlimit"); } return Qnil; }
建立當前進程作為新會話和進程組領導者,無控制tty;返回會話ID
Process.setsid # => 27422
不適用於所有平台。
static VALUE proc_setsid(VALUE _) { rb_pid_t pid; pid = setsid(); if (pid < 0) rb_sys_fail(0); return PIDT2NUM(pid); }
通過在該進程中執行以下操作之一創建新的子進程
-
將字符串
command_line
傳遞給 shell。 -
調用
exe_path
中的可執行文件。
如果使用不受信任的輸入調用此方法,則可能存在潛在的安全漏洞;請參見命令注入。
返回新進程的進程ID(pid),無需等待其完成。
為了避免殭屍進程,父進程應該調用以下方法之一
-
Process.wait
,以收集其子進程的終止狀態。 -
Process.detach
,以表明對其狀態不感興趣。
新進程是使用exec 系統調用創建的;它可能從調用程序繼承一些環境(可能包括打開的文件描述符)。
參數 env
,如果提供,是一個影響新進程的 ENV
的哈希;請參閱 執行環境。
參數 options
是一個用於新進程的選項哈希;請參閱 執行選項。
第一個必需的參數是以下之一
-
command_line
如果它是一個字符串,並且如果它以 shell 保留字開頭或特殊內置,或者如果它包含一個或多個元字符。 -
否則為
exe_path
。
參數 command_line
字符串參數 command_line
是要傳遞給 shell 的命令行;它必須以 shell 保留字開頭,以特殊內建開頭,或包含元字符
spawn('if true; then echo "Foo"; fi') # => 798847 # Shell reserved word. Process.wait # => 798847 spawn('echo') # => 798848 # Built-in. Process.wait # => 798848 spawn('date > /tmp/date.tmp') # => 798879 # Contains meta character. Process.wait # => 798849 spawn('date > /nop/date.tmp') # => 798882 # Issues error message. Process.wait # => 798882
命令行還可以包含用於該命令的參數和選項
spawn('echo "Foo"') # => 799031 Process.wait # => 799031
輸出
Foo
有關 shell 的詳細信息,請參見 Execution Shell。
如果新進程無法執行,則引發異常。
參數 exe_path
參數 exe_path
是以下之一
-
要調用的可執行文件的字符串路徑
spawn('/usr/bin/date') # Path to date on Unix-style system. Process.wait
輸出
Thu Aug 31 10:06:48 AM CDT 2023
-
包含可執行文件路徑和要用作執行進程名稱的字符串的2元素數組
pid = spawn(['sleep', 'Hello!'], '1') # 2-element array. p `ps -p #{pid} -o command=`
輸出
"Hello! 1\n"
Ruby直接調用可執行文件,無需shell和shell擴展。
如果給定一個或多個 args
,則每個都是要傳遞給可執行文件的參數或選項
spawn('echo', 'C*') # => 799392 Process.wait # => 799392 spawn('echo', 'hello', 'world') # => 799393 Process.wait # => 799393
輸出
C* hello world
如果新進程無法執行,則引發異常。
static VALUE rb_f_spawn(int argc, VALUE *argv, VALUE _) { rb_pid_t pid; char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' }; VALUE execarg_obj, fail_str; struct rb_execarg *eargp; execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE); eargp = rb_execarg_get(execarg_obj); fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name; pid = rb_execarg_spawn(execarg_obj, errmsg, sizeof(errmsg)); if (pid == -1) { int err = errno; rb_exec_fail(eargp, err, errmsg); RB_GC_GUARD(execarg_obj); rb_syserr_fail_str(err, fail_str); } #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV) return PIDT2NUM(pid); #else return Qnil; #endif }
返回包含當前進程及其子進程的用戶和系統CPU時間的Process::Tms
結構
Process.times # => #<struct Process::Tms utime=55.122118, stime=35.533068, cutime=0.0, cstime=0.002846>
精度由平台定義。
VALUE rb_proc_times(VALUE obj) { VALUE utime, stime, cutime, cstime, ret; #if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN) struct rusage usage_s, usage_c; if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0) rb_sys_fail("getrusage"); utime = DBL2NUM((double)usage_s.ru_utime.tv_sec + (double)usage_s.ru_utime.tv_usec/1e6); stime = DBL2NUM((double)usage_s.ru_stime.tv_sec + (double)usage_s.ru_stime.tv_usec/1e6); cutime = DBL2NUM((double)usage_c.ru_utime.tv_sec + (double)usage_c.ru_utime.tv_usec/1e6); cstime = DBL2NUM((double)usage_c.ru_stime.tv_sec + (double)usage_c.ru_stime.tv_usec/1e6); #else const double hertz = (double)get_clk_tck(); struct tms buf; times(&buf); utime = DBL2NUM(buf.tms_utime / hertz); stime = DBL2NUM(buf.tms_stime / hertz); cutime = DBL2NUM(buf.tms_cutime / hertz); cstime = DBL2NUM(buf.tms_cstime / hertz); #endif ret = rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime); RB_GC_GUARD(utime); RB_GC_GUARD(stime); RB_GC_GUARD(cutime); RB_GC_GUARD(cstime); return ret; }
返回當前進程的(實際)用戶ID。
Process.uid # => 1000
static VALUE proc_getuid(VALUE obj) { rb_uid_t uid = getuid(); return UIDT2NUM(uid); }
將當前進程的(用戶)用戶ID設置為new_uid
Process.uid = 1000 # => 1000
不適用於所有平台。
static VALUE proc_setuid(VALUE obj, VALUE id) { rb_uid_t uid; check_uid_switch(); uid = OBJ2UID(id); #if defined(HAVE_SETRESUID) if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0); #elif defined HAVE_SETREUID if (setreuid(uid, -1) < 0) rb_sys_fail(0); #elif defined HAVE_SETRUID if (setruid(uid) < 0) rb_sys_fail(0); #elif defined HAVE_SETUID { if (geteuid() == uid) { if (setuid(uid) < 0) rb_sys_fail(0); } else { rb_notimplement(); } } #endif return id; }
等待適當的子進程退出,返回其進程ID,並將$?
設置為包含有關該進程信息的Process::Status
對象。它等待哪個子進程取決於給定pid
的值
-
正整數:等待進程ID為
pid
的子進程pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 230866 pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 230891 Process.wait(pid0) # => 230866 $? # => #<Process::Status: pid 230866 exit 13> Process.wait(pid1) # => 230891 $? # => #<Process::Status: pid 230891 exit 14> Process.wait(pid0) # Raises Errno::ECHILD
-
0
:等待任何進程組ID與當前進程相同的子進程parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." end retrieved_pid = Process.wait(0) puts "Process.wait(0) returned pid #{retrieved_pid}, which is child 0 pid." begin Process.wait(0) rescue Errno::ECHILD => x puts "Raised #{x.class}, because child 1 process group ID differs from parent process group ID." end
輸出
Parent process group ID is 225764. Child 0 pid is 225788 Child 0 process group ID is 225764 (same as parent's). Child 1 pid is 225789 Child 1 process group ID is 225789 (different from parent's). Process.wait(0) returned pid 225788, which is child 0 pid. Raised Errno::ECHILD, because child 1 process group ID differs from parent process group ID.
-
-1
(默認):等待任何子進程parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." sleep 3 # To force child 1 to exit later than child 0 exit. end child_pids = [child0_pid, child1_pid] retrieved_pid = Process.wait(-1) puts child_pids.include?(retrieved_pid) retrieved_pid = Process.wait(-1) puts child_pids.include?(retrieved_pid)
輸出
Parent process group ID is 228736. Child 0 pid is 228758 Child 0 process group ID is 228736 (same as parent's). Child 1 pid is 228759 Child 1 process group ID is 228759 (different from parent's). true true
-
-1
以下:等待任何進程組ID為-pid
的子進程parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." end sleep 1 retrieved_pid = Process.wait(-child1_pid) puts "Process.wait(-child1_pid) returned pid #{retrieved_pid}, which is child 1 pid." begin Process.wait(-child1_pid) rescue Errno::ECHILD => x puts "Raised #{x.class}, because there's no longer a child with process group id #{child1_pid}." end
輸出
Parent process group ID is 230083. Child 0 pid is 230108 Child 0 process group ID is 230083 (same as parent's). Child 1 pid is 230109 Child 1 process group ID is 230109 (different from parent's). Process.wait(-child1_pid) returned pid 230109, which is child 1 pid. Raised Errno::ECHILD, because there's no longer a child with process group id 230109.
參數flags
應作為以下常量之一給出,或作為兩者的邏輯OR
-
Process::WNOHANG
:如果沒有子進程可用,則不阻塞。 -
Process:WUNTRACED:即使尚未報告,也可能返回已停止的子進程。
並非所有的旗標在所有平台上都可用。
如果沒有適合的子進程,則引發 Errno::ECHILD。
不適用於所有平台。
Process.waitpid
是 Process.wait
的別名。
static VALUE proc_m_wait(int c, VALUE *v, VALUE _) { return proc_wait(c, v); }
類似於 Process.waitpid
,但返回包含子進程 pid
和 Process::Status
status
的數組。
pid = Process.spawn('ruby', '-e', 'exit 13') # => 309581 Process.wait2(pid) # => [309581, #<Process::Status: pid 309581 exit 13>]
Process.waitpid2
是 Process.waitpid
的別名。
static VALUE proc_wait2(int argc, VALUE *argv, VALUE _) { VALUE pid = proc_wait(argc, argv); if (NIL_P(pid)) return Qnil; return rb_assoc_new(pid, rb_last_status_get()); }
等待所有子進程,返回包含 2 元素數組的數組;每個子數組包含一個整數 pid 和 Process::Status
狀態,代表一個已收割的子進程。
pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 325470 pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 325495 Process.waitall # => [[325470, #<Process::Status: pid 325470 exit 13>], [325495, #<Process::Status: pid 325495 exit 14>]]
static VALUE proc_waitall(VALUE _) { VALUE result; rb_pid_t pid; int status; result = rb_ary_new(); rb_last_status_clear(); for (pid = -1;;) { pid = rb_waitpid(-1, &status, 0); if (pid == -1) { int e = errno; if (e == ECHILD) break; rb_syserr_fail(e, 0); } rb_ary_push(result, rb_assoc_new(PIDT2NUM(pid), rb_last_status_get())); } return result; }
等待適當的子進程退出,返回其進程ID,並將$?
設置為包含有關該進程信息的Process::Status
對象。它等待哪個子進程取決於給定pid
的值
-
正整數:等待進程ID為
pid
的子進程pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 230866 pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 230891 Process.wait(pid0) # => 230866 $? # => #<Process::Status: pid 230866 exit 13> Process.wait(pid1) # => 230891 $? # => #<Process::Status: pid 230891 exit 14> Process.wait(pid0) # Raises Errno::ECHILD
-
0
:等待任何進程組ID與當前進程相同的子進程parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." end retrieved_pid = Process.wait(0) puts "Process.wait(0) returned pid #{retrieved_pid}, which is child 0 pid." begin Process.wait(0) rescue Errno::ECHILD => x puts "Raised #{x.class}, because child 1 process group ID differs from parent process group ID." end
輸出
Parent process group ID is 225764. Child 0 pid is 225788 Child 0 process group ID is 225764 (same as parent's). Child 1 pid is 225789 Child 1 process group ID is 225789 (different from parent's). Process.wait(0) returned pid 225788, which is child 0 pid. Raised Errno::ECHILD, because child 1 process group ID differs from parent process group ID.
-
-1
(默認):等待任何子進程parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." sleep 3 # To force child 1 to exit later than child 0 exit. end child_pids = [child0_pid, child1_pid] retrieved_pid = Process.wait(-1) puts child_pids.include?(retrieved_pid) retrieved_pid = Process.wait(-1) puts child_pids.include?(retrieved_pid)
輸出
Parent process group ID is 228736. Child 0 pid is 228758 Child 0 process group ID is 228736 (same as parent's). Child 1 pid is 228759 Child 1 process group ID is 228759 (different from parent's). true true
-
-1
以下:等待任何進程組ID為-pid
的子進程parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." end sleep 1 retrieved_pid = Process.wait(-child1_pid) puts "Process.wait(-child1_pid) returned pid #{retrieved_pid}, which is child 1 pid." begin Process.wait(-child1_pid) rescue Errno::ECHILD => x puts "Raised #{x.class}, because there's no longer a child with process group id #{child1_pid}." end
輸出
Parent process group ID is 230083. Child 0 pid is 230108 Child 0 process group ID is 230083 (same as parent's). Child 1 pid is 230109 Child 1 process group ID is 230109 (different from parent's). Process.wait(-child1_pid) returned pid 230109, which is child 1 pid. Raised Errno::ECHILD, because there's no longer a child with process group id 230109.
參數flags
應作為以下常量之一給出,或作為兩者的邏輯OR
-
Process::WNOHANG
:如果沒有子進程可用,則不阻塞。 -
Process:WUNTRACED:即使尚未報告,也可能返回已停止的子進程。
並非所有的旗標在所有平台上都可用。
如果沒有適合的子進程,則引發 Errno::ECHILD。
不適用於所有平台。
Process.waitpid
是 Process.wait
的別名。
static VALUE proc_m_wait(int c, VALUE *v, VALUE _) { return proc_wait(c, v); }
類似於 Process.waitpid
,但返回包含子進程 pid
和 Process::Status
status
的數組。
pid = Process.spawn('ruby', '-e', 'exit 13') # => 309581 Process.wait2(pid) # => [309581, #<Process::Status: pid 309581 exit 13>]
Process.waitpid2
是 Process.waitpid
的別名。
static VALUE proc_wait2(int argc, VALUE *argv, VALUE _) { VALUE pid = proc_wait(argc, argv); if (NIL_P(pid)) return Qnil; return rb_assoc_new(pid, rb_last_status_get()); }
通知 Ruby 虛擬機啟動序列已完成,現在是優化應用的好時機。這對於長時間運行的應用程序很有用。
預期應該在應用程序啟動結束時調用此方法。如果應用程序使用預先派生模型部署,則應在第一個分叉之前在原始進程中調用 Process.warmup
。
執行的實際優化完全是特定於實現的,並且未來可能會更改而不另行通知。
在 CRuby 上,Process.warmup
-
執行一個主要的
GC
。 -
壓縮堆。
-
將所有存活對象提升到老年代。
-
預先計算所有字符串的編碼範圍。
-
釋放所有空堆頁並將可分配頁計數器增加釋放的頁數。
-
如果可用,則調用
malloc_trim
以釋放空的 malloc 頁面。
static VALUE proc_warmup(VALUE _) { RB_VM_LOCK_ENTER(); rb_gc_prepare_heap(); RB_VM_LOCK_LEAVE(); return Qtrue; }