Process 模組

模組 Process 代表底層作業系統中的一個進程。其方法支持當前進程及其子進程的管理。

進程創建

以下每個方法都在新進程或子殼中執行給定的命令,或在新進程和/或子殼中執行多個命令。進程或子殼的選擇取決於命令的形式;請參閱參數 command_line 或 exe_path

另外

執行環境

可選的前導參數 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_lineexe_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 是以下之一

示例

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可以被指定為

有以下這些用於fds的速記符號

來源給定的值之一是

參見存取模式文件權限

環境變數(: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並選擇以下其中一個值:

僅在 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

這裡有什麼

當前處理程序的取得器

當前進程設置器

當前進程執行

子進程

處理程序群組

時間

常數

CLOCK_BOOTTIME

參見 Process.clock_gettime

CLOCK_BOOTTIME_ALARM

參見 Process.clock_gettime

CLOCK_MONOTONIC

參見 Process.clock_gettime

CLOCK_MONOTONIC_COARSE

參見 Process.clock_gettime

CLOCK_MONOTONIC_FAST

參見 Process.clock_gettime

CLOCK_MONOTONIC_PRECISE

參見 Process.clock_gettime

CLOCK_MONOTONIC_RAW

參見 Process.clock_gettime

CLOCK_MONOTONIC_RAW_APPROX

參見 Process.clock_gettime

CLOCK_PROCESS_CPUTIME_ID

參見 Process.clock_gettime

CLOCK_PROF

參見 Process.clock_gettime

CLOCK_REALTIME

參見 Process.clock_gettime

CLOCK_REALTIME_ALARM

參見 Process.clock_gettime

CLOCK_REALTIME_COARSE

參見 Process.clock_gettime

CLOCK_REALTIME_FAST

參見 Process.clock_gettime

CLOCK_REALTIME_PRECISE

參見 Process.clock_gettime

CLOCK_SECOND

參見 Process.clock_gettime

CLOCK_TAI

參見 Process.clock_gettime

CLOCK_THREAD_CPUTIME_ID

參見 Process.clock_gettime

CLOCK_UPTIME

參見 Process.clock_gettime

CLOCK_UPTIME_FAST

參見 Process.clock_gettime

CLOCK_UPTIME_PRECISE

參見 Process.clock_gettime

CLOCK_UPTIME_RAW

參見 Process.clock_gettime

CLOCK_UPTIME_RAW_APPROX

參見 Process.clock_gettime

CLOCK_VIRTUAL

參見 Process.clock_gettime

PRIO_PGRP

參見 Process.setpriority

PRIO_PROCESS

參見 Process.setpriority

PRIO_USER

參見 Process.setpriority

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

參見 Process.setrlimit

RLIM_SAVED_CUR

參見 Process.setrlimit

RLIM_SAVED_MAX

參見 Process.setrlimit

WNOHANG

參見 Process.wait

WUNTRACED

參見 Process.wait

公共類方法

_fork → integer 點擊切換源

fork 的內部API。請勿直接調用此方法。目前,通過 Kernel#forkProcess.forkIO.popen"-" 參數調用此方法。

此方法不適用於常規代碼,而適用於應用程序監控庫。您可以在 fork 事件之前和之後添加自定義代碼,方法是覆蓋此方法。

注意:可能會使用 fork(2) 實現 Process.daemon,但不會通過此方法進行。因此,根據您鉤入此方法的原因,您可能還想要鉤入該方法。參見 此問題 以獲得更詳細的討論。

VALUE
rb_proc__fork(VALUE _obj)
{
    rb_pid_t pid = proc_fork_pid();
    return PIDT2NUM(pid);
}
中止 點擊以切換來源
abort(msg = nil)

立即終止執行,效果上等同於呼叫 Kernel.exit(false)

如果給定字串參數 msg,則在終止之前將其寫入 STDERR;否則,如果引發了異常,則打印其消息和回溯。

static VALUE
f_abort(int c, const VALUE *a, VALUE _)
{
    rb_f_abort(c, a);
    UNREACHABLE_RETURN(Qnil);
}
argv0 → frozen_string 點擊以切換來源

返回正在執行的腳本的名稱。該值不受將新值分配給 $0 的影響。

此方法首次出現在 Ruby 2.1 中,用作全局變量自由方式以獲取腳本名稱。

static VALUE
proc_argv0(VALUE process)
{
    return rb_orig_progname;
}
clock_getres(clock_id, unit = :float_second) → number 點擊以切換來源

返回由 POSIX 函数 clock_getres() 確定的時鐘分辨率

Process.clock_getres(:CLOCK_REALTIME) # => 1.0e-09

參見 Process.clock_gettime 以獲取 clock_idunit 的值。

範例

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);
    }
}
clock_gettime(clock_id, unit = :float_second) → number 點擊以切換來源

返回由 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_SECCLOCKS_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);
}
daemon(nochdir = nil, noclose = nil) → 0 點擊以切換源

將當前進程與其控制終端分離,並將其作為系統守護進程在後台運行;返回零。

默認情況下

  • 將當前工作目錄更改為根目錄。

  • 將 $stdin、$stdout 和 $stderr 重定向到空設備。

如果可選參數 nochdirtrue,則不更改當前工作目錄。

如果可選參數 noclosetrue,則不重定向 $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);
}
detach(pid) → thread 點擊切換源

避免子進程成為殭屍進程的可能性。通過設置一個獨立的 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));
}
egid → 整數 點擊切換源
Process::GID.eid → 整數
Process::Sys.geteid → 整數

返回當前進程的有效組 ID

Process.egid # => 500

不適用於所有平台。

static VALUE
proc_getegid(VALUE obj)
{
    rb_gid_t egid = getegid();

    return GIDT2NUM(egid);
}
egid = new_egid → new_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;
}
euid → 整數 點擊切換源
Process::UID.eid → 整數
Process::Sys.geteuid → 整數

返回當前進程的有效用戶 ID。

Process.euid # => 501
static VALUE
proc_geteuid(VALUE obj)
{
    rb_uid_t euid = geteuid();
    return UIDT2NUM(euid);
}
euid = new_euid → new_euid 點擊切換源

設置當前進程的有效用戶 ID。

不適用於所有平台。

static VALUE
proc_seteuid_m(VALUE mod, VALUE euid)
{
    check_uid_switch();
    proc_seteuid(OBJ2UID(euid));
    return euid;
}
exec([env, ] command_line, options = {}) 點擊切換源
exec([env, ] exe_path, *args, options = {})

通過執行以下操作之一來替換當前進程

  • 將字符串 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);
}
exit(status = true) 點擊切換源碼
exit(status = true)

通過引發 SystemExit 來啟動 Ruby 腳本的終止;異常可能會被捕獲。將退出狀態 status 返回給底層操作系統。

對於參數 status ,值 truefalse 分別表示成功和失敗;整數值的含義是系統相依的。

示例

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);
}
exit!(status = false) 點擊切換源碼
exit!(status = false)

立即退出進程;不調用退出處理程序。將退出狀態 status 返回給底層操作系統。

Process.exit!(true)

對於參數 status ,值 truefalse 分別表示成功和失敗;整數值的含義是系統相依的。

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);
}
fork { ... } → 整數或 nil 點擊切換源碼
fork → 整數或 nil

創建一個子進程。

給定一個塊時,在子進程中運行該塊;在塊退出時,子進程以零狀態終止

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

為了避免殭屍進程,父進程應該調用以下方法之一

調用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);
}
getpgid(pid) → integer 點擊以切換源
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);
}
getpgrp → integer 點擊以切換源

返回當前進程的進程組 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
}
getpriority(kind, id) → integer 點擊以切換源

返回指定進程、進程組或用戶的調度優先級。

參數kind之一是

參數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);
}
getrlimit(resource) → [cur_limit, max_limit] 點擊以切換源

返回給定resource的當前(軟)限制和最大(硬)限制的2元素數組。

參數resource指定要返回其限制的資源;參見Process.setrlimit

返回值cur_limitmax_limit都是整數;參見Process.setrlimit

示例

Process.getrlimit(:CORE) # => [0, 18446744073709551615]

參見Process.setrlimit

不適用於所有平台。

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));
}
getsid(pid = nil) → integer 點擊以切換源

返回給定進程 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);
}
gid → integer 點擊以切換源
Process::GID.rid → integer
Process::Sys.getgid → integer

返回當前進程的(真實)組 ID

Process.gid # => 1000
static VALUE
proc_getgid(VALUE obj)
{
    rb_gid_t gid = getgid();
    return GIDT2NUM(gid);
}
gid = new_gid → new_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);
}
groups → array 點擊以切換源

返回當前進程的補充組訪問列表中的組 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;
}
groups = new_groups → new_groups 點擊切換來源

將補充群組存取清單設置為給定的群組 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);
}
initgroups(username, gid) → array 點擊切換來源

設置補充群組存取清單;新清單包含

  • 屬於由 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);
}
kill(signal, *ids) → count 點擊切換來源

對每個指定的 ids 進程發送一個信號(必須至少指定一個 ID);返回發送的信號計數。

對於每個給定的 id,如果 id

  • 正數,則將信號發送給其進程 ID 為 id 的進程。

  • 零,將信號發送給當前進程組中的所有進程。

  • 負數,將信號發送給系統相關的一組進程。

引數 signal 指定要發送的信號;引數可以是

  • 一個整數信號號:例如,-29029

  • 一個信號名稱(字符串),帶有或不帶有前導的 'SIG',以及帶有或不帶有進一步的前綴減號('-'):例如

    • 'SIGPOLL'.

    • 'POLL',

    • '-SIGPOLL'.

    • '-POLL'.

  • 一個信號符號,帶有或不帶有前導的 'SIG',以及帶有或不帶有進一步的前綴減號('-'):例如

    • :SIGPOLL.

    • :POLL.

    • :'-SIGPOLL'.

    • :'-POLL'.

如果 signal

  • 一個非負整數,或者不帶前綴 '-' 的信號名稱或符號,則對具有進程 ID id 的每個進程發送信號。

  • 一個負整數,或者帶有前綴 '-' 的信號名稱或符號,則對具有群組 ID id 的每個進程組發送信號。

使用方法 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);
}
last_status → Process::Status 或 nil 點擊切換來源

返回表示當前線程中最近退出的子進程的 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();
}
maxgroups → 整數 點擊切換來源

返回輔助組訪問列表中允許的最大組 ID 數。

Process.maxgroups # => 32
static VALUE
proc_getmaxgroups(VALUE obj)
{
    return INT2FIX(maxgroups());
}
maxgroups = new_max → new_max 點擊切換來源

設置輔助組訪問列表中允許的最大組 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);
}
pid → 整數 點擊切換來源

返回當前進程的進程 ID。

Process.pid # => 15668
static VALUE
proc_get_pid(VALUE _)
{
    return get_pid();
}
ppid → 整數 點擊切換來源

返回當前進程的父進程的進程 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();
}
setpgid(pid, pgid) → 0 點擊切換來源

將由進程 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);
}
setpgrp → 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);
}
setpriority(kind, 整數, priority) → 0 點擊切換來源

參見 Process.getpriority

範例

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);
}
setproctitle(字符串) → 字符串 點擊切換來源

設置顯示在 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);
}
setrlimit(resource, cur_limit, max_limit = cur_limit) → nil 點擊切換來源

為給定的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_limitmax_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;
}
setsid → integer 點擊以切換源代碼

建立當前進程作為新會話和進程組領導者,無控制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);
}
spawn([env, ] command_line, options = {}) → pid 點擊以切換源代碼
spawn([env, ] exe_path, *args, options = {}) → pid

通過在該進程中執行以下操作之一創建新的子進程

  • 將字符串 command_line 傳遞給 shell。

  • 調用 exe_path 中的可執行文件。

如果使用不受信任的輸入調用此方法,則可能存在潛在的安全漏洞;請參見命令注入

返回新進程的進程ID(pid),無需等待其完成。

為了避免殭屍進程,父進程應該調用以下方法之一

新進程是使用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
}
times → process_tms 點擊以切換源代碼

返回包含當前進程及其子進程的用戶和系統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;
}
uid → integer 點擊以切換源代碼
Process::UID.rid → integer
Process::Sys.getuid → integer

返回當前進程的(實際)用戶ID。

Process.uid # => 1000
static VALUE
proc_getuid(VALUE obj)
{
    rb_uid_t uid = getuid();
    return UIDT2NUM(uid);
}
uid = new_uid → new_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;
}
wait(pid = -1, flags = 0) → integer 點擊以切換源代碼

等待適當的子進程退出,返回其進程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.waitpidProcess.wait 的別名。

static VALUE
proc_m_wait(int c, VALUE *v, VALUE _)
{
    return proc_wait(c, v);
}
wait2(pid = -1, flags = 0) → [pid, status] 點擊切換源代碼

類似於 Process.waitpid,但返回包含子進程 pidProcess::Status status 的數組。

pid = Process.spawn('ruby', '-e', 'exit 13') # => 309581
Process.wait2(pid)
# => [309581, #<Process::Status: pid 309581 exit 13>]

Process.waitpid2Process.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());
}
waitall → array 點擊切換源代碼

等待所有子進程,返回包含 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;
}
wait(pid = -1, flags = 0) → integer 點擊以切換源代碼

等待適當的子進程退出,返回其進程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.waitpidProcess.wait 的別名。

static VALUE
proc_m_wait(int c, VALUE *v, VALUE _)
{
    return proc_wait(c, v);
}
wait2(pid = -1, flags = 0) → [pid, status] 點擊切換源代碼

類似於 Process.waitpid,但返回包含子進程 pidProcess::Status status 的數組。

pid = Process.spawn('ruby', '-e', 'exit 13') # => 309581
Process.wait2(pid)
# => [309581, #<Process::Status: pid 309581 exit 13>]

Process.waitpid2Process.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());
}
warmup → true 點擊切換源代碼

通知 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;
}