使用過命令列的同學都知道,我們使用命令列是一般是在shell中執行類似下面這樣的命令
/cmd/path/cmd_bin param1 param2 ... paramn
但是問題來了,任務排程系統又不能和shell互動,要怎樣調起這樣的命令呢?linux為我們提供了一套可行的方式,多程序。至於怎樣實現多程序的方式,我們從簡單到複雜來講吧
system()函式
在c標準庫中有乙個system()函式,在呼叫這個函式時,linux會產生乙個子程序,然後由子程序來呼叫/bin/sh-c string來執行引數string字串所代表的命令。命令執行完後子程序退出,隨即返回原呼叫的程序。這個函式的原型如下
int system(const char * string);
產生乙個子程序並執行引數中的命令列。引數string即要執行的命令
通過上面的分析可知,system()函式是完成能夠滿足我們的基本需求的,只要我們把要執行的命令拼裝成乙個命令列,然後傳到system()函式即可。像下面例子所示
#include int main ()
但是,由於system()在命令執行完之前是會阻塞主程序的,這對於多個任務同時執行,而且任務都需要執行很長時間,並且我們需要知道每個任務的執行結果的情況下,system()就不能很好地滿足我們的需求了。雖然不能直接使用,但是我們可以參考下system()函式是怎樣實現的。
//c_standard_lib/stdlib/system.c
/* unix system calls */
int _execl(const char *, const char *, ...);
int _fork(void);
int _wait (int *);
int (system)(const char *s)
else /* continue here as parent */
while (_wait(null) != pid)
; /* wait for child */
} return (-1);
}
從上面c標準庫的**中可以看到,在實現system()函式中使用到了3個其他系統函式,分別是fork(),execl()和wait()。既然如此,我們就順勢而為,看看能不能也使用這三個函式來實現乙個滿足我們要求的做法。
自己動手,豐衣足食
上面我們知道了system()函式的用到了哪些系統呼叫,我們接下來就先熟悉下這些系統呼叫好了,原型如下
pid_t fork(void);
fork()系統呼叫會通過複製乙個現有程序來建立乙個全新的程序。返回值:自程序中返回0,父程序返回程序id,出錯返回-1
int execl(const char *pathname, const char *arg, ... /* (char *) null */);
int execlp(const char *file, const char *arg, ... /* (char *) null */);
int execle(const char *pathname, const char *arg, ... /*, (char *) null, char * const envp */);
int execv(const char *pathname, char *const ar**);
int execvp(const char *file, char *const ar**);
int execvpe(const char *file, char *const ar**, char *const envp);
在程序的建立上unix採用了乙個獨特的方法,它將程序建立與載入乙個新程序映象分離。
當我們建立了乙個程序之後,通常將子程序替換成新的程序映象,這可以用exec系列的函式來進行。
當然,exec系列的函式也可以將當前程序替換掉。path引數表示你要啟動程式的名稱包括路徑名
arg引數表示啟動程式所帶的引數,一般第乙個引數為要執行命令名,不是帶路徑且arg必須以null結束
返回值:成功返回0,失敗返回-1
上述exec系列函式底層都是通過execve系統呼叫實現:
int execve(const char *filename, char *const ar**,char *const envp);
pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);
系統呼叫exit後,該程序並非馬上消失,而是留下乙個叫殭屍程序的資料結構,殭屍程序是非常特使的一種,它放棄了幾乎所有的記憶體空間,
沒有任何可執行**,也不能別排程,僅僅在程序列表保留位置,而且不占用任何記憶體空間。
wait()函式用於使父程序阻塞,直到乙個子程序結束或者該程序接收到了乙個指定的訊號為止。
如果該父程序沒有子程序或者它的子程序已經結束,則wait()函式就會立即返回。
waitpid()的作用和wait()一樣,但它並不一定要等待第乙個終止的子程序(它可以通過pid指定需要等待終止的子程序),它還有若干options,
當options==wnohang時,相當於提供乙個非阻塞版本的 wait()功能,也能支援作業控制。
實際上,wait()函式只是 waitpid()函式的乙個特例,在linux 內部實現 wait()函式時直接呼叫的就是waitpid()函式
下面是乙個簡單的應用例子,在實際的應用中,除了這3個api的應用之外,還需要做很多其他的事情,如註冊訊號,寫日誌,管道重定向等等,有興趣的同學可以看看apue或者《linux系統程式設計》等等經典著作,這裡就不再囉嗦了。
#include #include #include #include #include #include #include #include #include #include #include #include #include #include int exec( const std::string& execname, std::vector& params)
ar**[argc] = null;
/*** step 3. fork and exec
*/pid_t pid = fork();
if (pid == 0)
else if (pid > 0)
// get exit value of child process
int exit_value = 0;
if (wifexited(status))
else if (wifsignaled(status))
else
exit_value = 0xf0;
return exit_value;
} return -1;
}
怎樣做到的
本來打算對上述api的實現剖析一番的,但是想到自己已經很就沒有去看這麼底層的東西了,而且linux核心版本更新得很快,所以就放棄了,只能奉上幾個api在核心中的實現**,有興趣的同學自行學習好了
fork()核心實現elixir.bootlin.com
waitpid核心實現elixir.bootlin.com
execve核心**elixir.bootlin.com
PHP多程序處理並行處理任務例項
本文目的 本文通過例子講解linux環境下,使用php進行併發任務處理,以及如何通過pipe用於程序間的資料同步。寫得比較簡單,作為備忘錄。php多程序 通過pcntl 系列函式使用多程序功能。注意 pcntl 只能執行在php cli 命令列 環境下,在web伺服器環境下,會出現無法預期的結果,請...
6 2Process 多程序實現多工
程序實現多工時浪費資源 主程序 占用資源 子程序1 複製主程序 占用資源 子程序2 複製主程序 占用資源 coding utf 8 import threading import time import multiprocessing def test1 子程序1 while true print ...
PHP使用QPM實現多程序並行任務處理程式
考慮用php實現以下場景 有乙個抓站的url列表儲存在佇列裡,後台程式讀取這個佇列,然後轉交給子程序去抓取html存放到檔案裡。為了提高效率,允許多工並行執行,但為了避免機器負載過高,限制了最大的並行任務數 為了測試方便,我們把這個數設為3 當佇列中取到 end標記時,程式結束執行。這個場景用qpm...