#include stdio.h
網站建設哪家好,找創新互聯公司!專注于網頁設計、網站建設、微信開發、小程序定制開發、集團企業網站建設等服務項目。為回饋新老客戶創新互聯還提供了崇義免費建站歡迎大家使用!
main()
{
int i,r,p1,p2,fd[2];
char buf[50],s[50];
pipe(fd); //創建匿名管道,fd[0]為讀端,fd[1]為寫端
while((p1=fork())==-1); //創建子進程P1,直至成功為止(p1!=-1)
if(p1==0) //子進程P1執行邏輯
{
lockf(fd[1],1,0); //鎖定管道寫端,保證寫入數據的完整性
sprintf(buf,"child process P1 is sending messages!\n"); //在buf中填入準備寫入管道的信息數據
printf("child processP1!\n"); //打印“子進程P1正在運行”
write(fd[1],buf,50); //向管道寫端fd[1]寫入buf中的數據,寫完后該數據即可以從讀端fd[0]讀出
sleep(5); //睡眠5秒
lockf(fd[1],0,0); //解鎖管道寫端
exit(0); //子進程P1退出
}
else //主進程的執行邏輯
{
while((p2=fork())==-1); //創建第二個子進程P2
if(p2==0) //子進程P2的執行邏輯
{
lockf(fd[1],1,0); //鎖定管道寫端,保證數據寫入完整
sprintf(buf,"child process P2 is sending messages!\n"); //在buf中填入準備寫入管道的信息數據
printf("child processP2!\n"); //打印“子進程P2正在運行”
write(fd[1],buf,50); //向管道寫端fd[1]寫入buf中的數據,寫完后該數據即可從讀端fd[0]讀出
sleep(5); //睡眠5秒
lockf(fd[1],0,0); //解鎖管道寫端
exit(0); //子進程P2退出
}
//以下為主進程執行邏輯
wait(0); //等待某個子進程退出
if(r=read(fd[0],s,50)==-1) //從管道讀端fd[0]讀取P1或者P2寫入的數據(視哪個子進程搶先執行到lockf函數)
{
printf(:can't read pipe\n"); //讀取失敗,打印錯誤信息
}
else
{
printf(:%s\n",s); //打印出讀到的信息數據
}
wait(0); //等待第二個子進程退出
if(r=read(fd[0],s,50)==-1) //從管道讀端fd[0]讀取出P1或者P2寫入的數據(視哪個子進程后執行到lockf函數)
{
printf(:can't read pipe\n"); //讀取失敗,打印錯誤信息
}
else
{
printf(:%s\n",s); //打印讀取到的信息數據
}
exit(0); //主進程退出
}
}
總的說來,就是主進程創建了兩個子進程P1、P2,這兩個子進程分別向管道寫入了一行文字,然后主進程從管道另一端將這兩行文字讀出并打印出來
由于進程的并發執行性,哪個子進程的信息先寫到管道是隨機的,因此該程序每次運行的輸出可能并不相同,兩行文字之間可能會相互交換
#include windows.h
BOOL CreateProcess
(
LPCTSTRlpApplicationName,
LPTSTRlpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes。
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
詳見百度百科
所在函數庫為stdlib.h、process.h
void abort() 此函數通過調用具有出口代碼3的_exit寫一個終止信息于
stderr,并異常終止程序 無返回值
int exec…裝入和運行其它程序
int execl( char *pathname,char *arg0,char *arg1,…,char *argn,NULL)
int execle( char *pathname,char *arg0,char *arg1,…,
char *argn,NULL,char *envp[])
int execlp( char *pathname,char *arg0,char *arg1,…,NULL)
int execlpe(char *pathname,char *arg0,char *arg1,…,NULL,char *envp[])
int execv( char *pathname,char *argv[])
int execve( char *pathname,char *argv[],char *envp[])
int execvp( char *pathname,char *argv[])
int execvpe(char *pathname,char *argv[],char *envp[])
exec函數族裝入并運行程序pathname,并將參數
arg0(arg1,arg2,argv[],envp[])傳遞給子程序,出錯返回-1
在exec函數族中,后綴l、v、p、e添加到exec后,
所指定的函數將具有某種操作能力
有后綴 p時,函數可以利用DOS的PATH變量查找子程序文件
l時,函數中被傳遞的參數個數固定
v時,函數中被傳遞的參數個數不固定
e時,函數傳遞指定參數envp,允許改變子進程的環境,
無后綴e時,子進程使用當前程序的環境
void _exit(int status)終止當前程序,但不清理現場
void exit(int status) 終止當前程序,關閉所有文件,寫緩沖區的輸出(等待輸出),
并調用任何寄存器的出口函數,無返回值
int spawn…運行子程序
int spawnl( int mode,char *pathname,char *arg0,char *arg1,…,
char *argn,NULL)
int spawnle( int mode,char *pathname,char *arg0,char *arg1,…,
char *argn,NULL,char *envp[])
int spawnlp( int mode,char *pathname,char *arg0,char *arg1,…,
char *argn,NULL)
int spawnlpe(int mode,char *pathname,char *arg0,char *arg1,…,
char *argn,NULL,char *envp[])
int spawnv( int mode,char *pathname,char *argv[])
int spawnve( int mode,char *pathname,char *argv[],char *envp[])
int spawnvp( int mode,char *pathname,char *argv[])
int spawnvpe(int mode,char *pathname,char *argv[],char *envp[])
spawn函數族在mode模式下運行子程序pathname,并將參數
arg0(arg1,arg2,argv[],envp[])傳遞給子程序.出錯返回-1
mode為運行模式
mode為 P_WAIT 表示在子程序運行完后返回本程序
P_NOWAIT 表示在子程序運行時同時運行本程序(不可用)
P_OVERLAY表示在本程序退出后運行子程序
在spawn函數族中,后綴l、v、p、e添加到spawn后,
所指定的函數將具有某種操作能力
有后綴 p時, 函數利用DOS的PATH查找子程序文件
l時, 函數傳遞的參數個數固定.
v時, 函數傳遞的參數個數不固定.
e時, 指定參數envp可以傳遞給子程序,允許改變子程序運行環境.
當無后綴e時,子程序使用本程序的環境.
int system(char *command) 將MSDOS命令command傳遞給DOS執行
轉換子程序,函數庫為math.h、stdlib.h、ctype.h、float.h
char *ecvt(double value,int ndigit,int *decpt,int *sign)
將浮點數value轉換成字符串并返回該字符串
char *fcvt(double value,int ndigit,int *decpt,int *sign)
將浮點數value轉換成字符串并返回該字符串
char *gcvt(double value,int ndigit,char *buf)
將數value轉換成字符串并存于buf中,并返回buf的指針
char *ultoa(unsigned long value,char *string,int radix)
將無符號整型數value轉換成字符串并返回該字符串,radix為轉換時所用基數
char *ltoa(long value,char *string,int radix)
將長整型數value轉換成字符串并返回該字符串,radix為轉換時所用基數
char *itoa(int value,char *string,int radix)
將整數value轉換成字符串存入string,radix為轉換時所用基數
double atof(char *nptr) 將字符串nptr轉換成雙精度數,并返回這個數,錯誤返回0
int atoi(char *nptr) 將字符串nptr轉換成整型數, 并返回這個數,錯誤返回0
long atol(char *nptr) 將字符串nptr轉換成長整型數,并返回這個數,錯誤返回0
double strtod(char *str,char **endptr)將字符串str轉換成雙精度數,并返回這個數,
long strtol(char *str,char **endptr,int base)將字符串str轉換成長整型數,
并返回這個數,
int toascii(int c) 返回c相應的ASCII
int tolower(int ch) 若ch是大寫字母('A'-'Z')返回相應的小寫字母('a'-'z')
int _tolower(int ch) 返回ch相應的小寫字母('a'-'z')
int toupper(int ch) 若ch是小寫字母('a'-'z')返回相應的大寫字母('A'-'Z')
int _toupper(int ch) 返回ch相應的大寫字母('A'-'Z')
WIN32API函數CreateProcess用來創建一個新的進程和它的主線程,這個新進程運行指定的可執行文件。
函數原型:
BOOL CreateProcess
(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes。
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATIONlpProcessInformation
);
參數:
lpApplicationName
指向一個NULL結尾的、用來指定可執行模塊的字符串。
這個字符串可以是可執行模塊的絕對路徑,也可以是相對路徑,在后一種情況下,函數使用當前驅動器和目錄建立可執行模塊的路徑。
這個參數可以被設為NULL,在這種情況下,可執行模塊的名字必須處于 lpCommandLine 參數最前面并由空格符與后面的字符分開。
lpCommandLine
指向一個以NULL結尾的字符串,該字符串指定要執行的命令行。
這個參數可以為空,那么函數將使用lpApplicationName參數指定的字符串當做要運行的程序的命令行。
如果lpApplicationName和lpCommandLine參數都不為空,那么lpApplicationName參數指定將要被運行的模塊,lpCommandLine參數指定將被運行的模塊的命令行。新運行的進程可以使用GetCommandLine函數獲得整個命令行。C語言程序可以使用argc和argv參數。
lpProcessAttributes
指向一個SECURITY_ATTRIBUTES結構體,這個結構體決定是否返回的句柄可以被子進程繼承。如果lpProcessAttributes參數為空(NULL),那么句柄不能被繼承。
在Windows NT中:SECURITY_ATTRIBUTES結構的lpSecurityDescriptor成員指定了新進程的安全描述符,如果參數為空,新進程使用默認的安全描述符。
lpThreadAttributes
同lpProcessAttribute,不過這個參數決定的是線程是否被繼承.通常置為NULL.
bInheritHandles
指示新進程是否從調用進程處繼承了句柄。
如果參數的值為真,調用進程中的每一個可繼承的打開句柄都將被子進程繼承。被繼承的句柄與原進程擁有完全相同的值和訪問權限。
dwCreationFlags
指定附加的、用來控制優先類和進程的創建的標志。以下的創建標志可以以除下面列出的方式外的任何方式組合后指定。
⑴值:CREATE_DEFAULT_ERROR_MODE
含義:新的進程不繼承調用進程的錯誤模式。CreateProcess函數賦予新進程當前的默認錯誤模式作為替代。應用程序可以調用SetErrorMode函數設置當前的默認錯誤模式。
這個標志對于那些運行在沒有硬件錯誤環境下的多線程外殼程序是十分有用的。
對于CreateProcess函數,默認的行為是為新進程繼承調用者的錯誤模式。設置這個標志以改變默認的處理方式。
⑵值:CREATE_NEW_CONSOLE
含義:新的進程將使用一個新的控制臺,而不是繼承父進程的控制臺。這個標志不能與DETACHED_PROCESS標志一起使用。
⑶值:CREATE_NEW_PROCESS_GROUP
含義:新進程將是一個進程樹的根進程。進程樹中的全部進程都是根進程的子進程。新進程樹的用戶標識符與這個進程的標識符是相同的,由lpProcessInformation參數返回。進程樹經常使用GenerateConsoleCtrlEvent函數允許發送CTRL+C或CTRL+BREAK信號到一組控制臺進程。
⑷值:CREATE_SEPARATE_WOW_VDM
如果被設置,新進程將會在一個私有的虛擬DOS機(VDM)中運行。另外,默認情況下所有的16位Windows應用程序都會在同一個共享的VDM中以線程的方式運行。單獨運行一個16位程序的優點是一個應用程序的崩潰只會結束這一個VDM的運行;其他那些在不同VDM中運行的程序會繼續正常的運行。同樣的,在不同VDM中運行的16位Windows應用程序擁有不同的輸入隊列,這意味著如果一個程序暫時失去響應,在獨立的VDM中的應用程序能夠繼續獲得輸入。
⑸值:CREATE_SHARED_WOW_VDM
如果WIN.INI中的Windows段的DefaultSeparateVDM選項被設置為真,這個標識使得CreateProcess函數越過這個選項并在共享的虛擬DOS機中運行新進程。
⑹值:CREATE_SUSPENDED
含義:新進程的主線程會以暫停的狀態被創建,直到調用ResumeThread函數被調用時才運行。
⑺值:CREATE_UNICODE_ENVIRONMENT
含義:如果被設置,由lpEnvironment參數指定的環境塊使用Unicode字符,如果為空,環境塊使用ANSI字符。
⑻值:DEBUG_PROCESS
含義:如果這個標志被設置,調用進程將被當做一個調試程序,并且新進程會被當做被調試的進程。系統把被調試程序發生的所有調試事件通知給調試器。
如果你使用這個標志創建進程,只有調用進程(調用CreateProcess函數的進程)可以調用WaitForDebugEvent函數。
⑼值:DEBUG_ONLY_THIS_PROCESS
含義:如果此標志沒有被設置且調用進程正在被調試,新進程將成為調試調用進程的調試器的另一個調試對象。如果調用進程沒有被調試,有關調試的行為就不會產生。
⑽值:DETACHED_PROCESS
含義:對于控制臺進程,新進程沒有訪問父進程控制臺的權限。新進程可以通過AllocConsole函數自己創建一個新的控制臺。這個標志不可以與CREATE_NEW_CONSOLE標志一起使用。
〔11〕值:CREATE_NO_WINDOW
含義:系統不為新進程創建CUI窗口,使用該標志可以創建不含窗口的CUI程序。
dwCreationFlags參數
還用來控制新進程的優先類,優先類用來決定此進程的線程調度的優先級。如果下面的優先級類標志都沒有被指定,那么默認的優先類是NORMAL_PRIORITY_CLASS,除非被創建的進程是IDLE_PRIORITY_CLASS。在這種情況下子進程的默認優先類是IDLE_PRIORITY_CLASS。
可以選擇下面的標志中的一個:
優先級:HIGH_PRIORITY_CLASS
含義:指示這個進程將執行時間臨界的任務,所以它必須被立即運行以保證正確。這個優先級的程序優先于正常優先級或空閑優先級的程序。一個例子是Windows任務列表,為了保證當用戶調用時可以立刻響應,放棄了對系統負荷的考慮。確保在使用高優先級時應該足夠謹慎,因為一個高優先級的CPU關聯應用程序可以占用幾乎全部的CPU可用時間。
優先級:IDLE_PRIORITY_CLASS
含義:指示這個進程的線程只有在系統空閑時才會運行并且可以被任何高優先級的任務打斷。例如屏幕保護程序。空閑優先級會被子進程繼承。
優先級:NORMAL_PRIORITY_CLASS
含義:指示這個進程沒有特殊的任務調度要求。
優先級:REALTIME_PRIORITY_CLASS
含義:指示這個進程擁有可用的最高優先級。一個擁有實時優先級的進程的線程可以打斷所有其他進程線程的執行,包括正在執行重要任務的系統進程。例如,一個執行時間稍長一點的實時進程可能導致磁盤緩存不足或鼠標反映遲鈍。
lpEnvironment
指向一個新進程的環境塊。如果此參數為空,新進程使用調用進程的環境。
一個環境塊存在于一個由以NULL結尾的字符串組成的塊中,這個塊也是以NULL結尾的。每個字符串都是name=value的形式。
因為相等標志被當做分隔符,所以它不能被環境變量當做變量名。
與其使用應用程序提供的環境塊,不如直接把這個參數設為空,系統驅動器上的當前目錄信息不會被自動傳遞給新創建的進程。對于這個情況的探討和如何處理,請參見注釋一節。
環境塊可以包含Unicode或ANSI字符。如果lpEnvironment指向的環境塊包含Unicode字符,那么dwCreationFlags字段的CREATE_UNICODE_ENⅥRONMENT標志將被設置。如果塊包含ANSI字符,該標志將被清空。
請注意一個ANSI環境塊是由兩個零字節結束的:一個是字符串的結尾,另一個用來結束這個快。一個Unicode環境塊是由四個零字節結束的:兩個代表字符串結束,另兩個用來結束塊。
lpCurrentDirectory
指向一個以NULL結尾的字符串,這個字符串用來指定子進程的工作路徑。這個字符串必須是一個包含驅動器名的絕對路徑。如果這個參數為空,新進程將使用與調用進程相同的驅動器和目錄。這個選項是一個需要啟動應用程序并指定它們的驅動器和工作目錄的外殼程序的主要條件。
lpStartupInfo
指向一個用于決定新進程的主窗體如何顯示的STARTUPINFO結構體。
lpProcessInformation
指向一個用來接收新進程的識別信息的PROCESS_INFORMATION結構體。
返回值:
如果函數執行成功,返回非零值。
如果函數執行失敗,返回零,可以使用GetLastError函數獲得錯誤的附加信息。
進程的查看、創建和撤銷(C語言)
例程:
#include?stdio.h
#include?windows.h
#includetlhelp32.h
int?showallproc()
{
PROCESSENTRY32?pe32;//用來存儲進程信息的結構體
pe32.dwSize=sizeof(pe32);
HANDLE?hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);//獲取進程快照
if(hProcessSnap==INVALID_HANDLE_VALUE)
{
printf("調用失敗\n");
return?1;
}
BOOL?bProc=Process32First(hProcessSnap,pe32);
while(bProc)
{
printf("%5d?%s\n",pe32.th32ProcessID,pe32.szExeFile);//輸出進程ID和進程名
bProc=Process32Next(hProcessSnap,pe32);
}
CloseHandle(hProcessSnap);
return?0;
}
int?creatproc()
{
char?str[256]={0};
printf("請輸入可執行文件路徑(*.exe):\n");
scanf("?%s",str);
STARTUPINFO?si={0};
si.cb=sizeof(STARTUPINFO);
si.dwFlags=STARTF_USESHOWWINDOW;
si.wShowWindow=SW_SHOW;
PROCESS_INFORMATION?pi;
if?(!CreateProcess(NULL,str,NULL,NULL,FALSE,0,NULL,NULL,si,pi))
{
printf("創建失敗\n");
return?-1;
}
else
{
printf("創建成功\n");
printf("進程號:%d\n",pi.dwProcessId);
}
return?0;
}
int?stopproc()
{
DWORD?ProcessID;
printf("請輸入想要終止的進程ID\n");
scanf("?%d",ProcessID);
HANDLE?hProcess=OpenProcess(PROCESS_TERMINATE,FALSE,ProcessID);//打開對應進程句柄
if?(hProcess==NULL)
{
printf("失敗\n");
return?-1;
}
if?(!TerminateProcess(hProcess,0))//關閉進程
{
printf("關閉失敗\n");
}
else
{
printf("關閉成功\n");
}
CloseHandle(hProcess);
return?0;
}
int?main()
{
int?n=0;
while(n!=4)
{
printf("1?查看進程\n");
printf("2?創建進程\n");
printf("3?終止進程\n");
printf("4?結束\n");
printf("請選擇:");
scanf("?%d",n);
switch(n)
{
case?1:
showallproc();
break;
case?2:
creatproc();
break;
case?3:
stopproc();
break;
case?4:
break;
default:
printf("輸入有誤!\n");
break;
}
}
return?0;
}
c語言調用函數while((p1=fork())==-1)的意思是:
fork函數是在當前進程中新建立一個子進程,如果這個創建子進程失敗,那么返回-1,這個實際是把創建進程的返回值和-1比較看看是否創建失敗。
因為是寫在while語句里,那么當創建失敗之后,如果在while里面沒有break或者跳出,當while執行體執行結束后又會執行(p1=fork())==-1,等于不斷重復創建子進程一直到創建成功為止。
注意這里會返回兩次,因為父進程創建子進程的時候復制了父進程的地址空間,那么父子進程地址空間的語句執行都在等待fork返回的那句話里。
所以返回兩次是父進程返回一個,返回的是子進程的ID,子進程返回一次,返回的是0.
那么我們根據不同的返回值就可以分別寫出我們想要的父子進程的邏輯。
#include stdio.h
#include stdlib.h
#include unistd.h
int main()
{
int pid1, pid2, pid3, pid4, pid5, pid6;
pid1 = getpid();
printf("PID = %d\n", pid1);
pid2 = fork();
if (pid2 == 0)
{
printf("PID = %d, Parent PID = %d\n", getpid(), getppid());
sleep(30);
exit(0);
}
pid3 = fork();
if (pid3 == 0)
{
printf("PID = %d, Parent PID = %d\n", getpid(), getppid());
pid5 = fork();
if (pid5 == 0)
{
printf("PID = %d, Parent PID = %d\n", getpid(), getppid());
pid6 = fork();
if (pid6 == 0)
{
printf("PID = %d, Parent PID = %d\n", getpid(), getppid());
sleep(30);
exit(0);
}
sleep(30);
exit(0);
}
sleep(30);
exit(0);
}
pid4 = fork();
if (pid4 == 0)
{
printf("PID = %d, Parent PID = %d\n", getpid(), getppid());
sleep(30);
exit(0);
}
sleep(30);
return 0;
}
每一個進程都會在退出前 sleep 30秒,從而保證能夠用 ps 看到,
編譯 gcc testpid.c -o testpid
然后執行,可以看到
PID = 24913
PID = 24914, Parent PID = 24913
PID = 24916, Parent PID = 24913
PID = 24915, Parent PID = 24913
PID = 24917, Parent PID = 24915
PID = 24918, Parent PID = 24917
ps -ef 的結果
24913 24582 0 11:29 pts/19 00:00:00 ./testpid
24914 24913 0 11:29 pts/19 00:00:00 ./testpid
24915 24913 0 11:29 pts/19 00:00:00 ./testpid
24916 24913 0 11:29 pts/19 00:00:00 ./testpid
24917 24915 0 11:29 pts/19 00:00:00 ./testpid
24918 24917 0 11:29 pts/19 00:00:00 ./testpid