我是linux编程的初学者,进程编程是linux编程首先要学习的东西,往后要学习进程之间通讯的一些编程。下面的是进程编程的一些基本函数以及他们的相关注释。
1.用户标识(UID)和有效用户标识(EUID)
使用getuid函数和geteuid函数来获取当前进程的用户标识和有效用户标识
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(void){
printf("Current process UID : %ld\n",(long)getuid());
printf("Current porcess EUID : %ld\n",(long)geteuid());
return 0;
}
运行结果:
Current process UID:500
Current process EUID:500
2. fork函数
通过fork函数并判断函数返回值,根据返回值来判断是在父进程还是子进程。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void){
pid_t pid;
//fork函数如果返回值小于0,表示调用失败
//如果返回值为0,表示处于进程中,如果大于0,表示在父进程中
if((pid=fork())<0){
perror("Cannot create the new process");
return 1;
}else if(pid==0){
printf("In the child process!\n");
return 0;
}else {
printf("In the parent process!\n");
return 0;
}
}
运行结果:
In the child processs!!
In the parent process!!
我的运行结果是:
In the parent process!
In the child processs!
父进程和子进程到底哪个先执行?
创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。
调用fork函数后,其后代码会被父子进程分别执行。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void){
fork();
printf("Will be executed twice\n");
return 0;
}
运行结果:
Will be excuted twice
Will be excuted twice
3. vfork函数
首先定义g_var为全局变量, var为局部变量,然后调用fork函数创建子进程,并在子进程对g_var变量和var变量进行修改。子进程在输出这两个变量值后退出,输出父进程中的这两个变量的取值情况。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int g_var=0;
int main(void){
pid_t pid;
int var=1;
printf("process id:%ld\n",(long)getpid());
printf("before execute the fork system call, g_var=%d var=%d\n",g_var,var);
if((pid=fork())<0)
{
perror("Cannot create a new process");
return 1;
}
else if(pid==0)
{
g_var++;
var++;
printf("process id : %ld, g_var=%d var=%d\n",(long)getpid(),g_var,var);
_exit(0);
}
else
printf("process id : %ld, g_var=%d var=%d\n",(long)getpid(),g_var,var);
return 0;
}
运行结果:
Process id :24437
Before excute the fork system call,g_var=0 var=1
Process id :24438, g_var=1 var=2
Process id :24437, g_var=0 var=1
//我的是先执行父进程 再执行子进程
修改上面的程序,将fork函数的语句进行替换,使用vfork函数,将代码保存并运行
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int g_var=0;
int main(void){
pid_t pid;
int var=1;
printf("process id:%ld\n",(long)getpid());
printf("before execute the fork system call, g_var=%d var=%d\n",g_var,var);
if((pid=vfork())<0){
perror("Cannot create a new process");
return 1;
}else if(pid==0){
g_var++;
var++;
printf("process id : %ld, g_var=%d var=%d\n",(long)getpid(),g_var,var);
_exit(0);
}
printf("process id : %ld, g_var=%d var=%d\n",(long)getpid(),g_var,var);
return 0;
}
运行结果:
Process id :24574
Before excute the fork system call,g_var=0 var=1
Process child id :24575, g_var=1 var=2
Process parent id :24574, g_var=1 var=2
4 exec 函数族
execvp函数支持参数列表,使用参数列表将使程序获得更大的灵活性,程序通过读取agrv中的参数,实现对输入的shell命令的执行。
#include <stdio.h>
#include <unistd.h>
int main(int argc,char* argv[]){
if(argc<2){
printf("Usage: %s path\n",argv[0]);
return 1;
}
execlp("/bin/ls","ls",argv[1],(char*)NULL);
return 0;
}
通过命令行:
gcc exec.c -o exec
./exec
执行结果:Usage: ./exec path
5 exit函数
使用atexit注册了一个在进程退出时的处理函数,该处理函数只是显示一段文字信息。Main函数退出时将调用exit函数,这样进程就会在退出时自动调用atexit注册的处理函数。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void do_at_exit(void)
{
printf("You can see the output when the program terminates\n");
}
int main(){
int flag;
flag=atexit(do_at_exit);//atexit 登记一个函数,当程序使用exit正常退出时被登记的函数自动被调用.
if (flag != 0) {
printf("Cannot set exit function\n");
return EXIT_FAILURE;//EXIT_FAILURE经库函数stdlib.h转换为一个非0值 用来指示程序失败的结束,一般用于exit().
}
exit(EXIT_SUCCESS);//EXIT_SUCCESS 经库函数stdlib.h转换为一个0值 用来指示程序成功的结束,一般用于exit()..
}
输出结果:You can see the output when the program terminates
进程控制/与运行环境的沟通:
atexit:登记一个函数,当程序使用exit正常退出时被登记的函数自动被调用.
exit :程序正常终止。首先atexit()登记的函数按照登记的逆序被调用;如果多次调用atexit登记了多个函数,按照登记的逆序调用这些函数。如果一个函数被登记了多次,则程序正常退出时该函数也将被调用多次。然后所有缓冲区中的数据被写回(flushed);所有打开着的流被关闭;tmpfile函数创建的文件被删除。最后,控制权返回给调用环境,返回数值表示程序返回时的状态,0表示EXIT_SUCCESS, 1表示EXIT_FAILURE.
6 _exit函数
下面的程序和上面的除了退出函数不同,其他都一样。不同的是使用_exit函数退出时,不会执行atexit中注册的处理函数
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void do_at_exit(void)
{
printf("You can see the output when the program terminates\n");
}
int main(){
int flag;
flag=atexit(do_at_exit);
if (flag != 0) {
printf("Cannot set exit function\n");
return EXIT_FAILURE;
}
_exit(EXIT_SUCCESS);//_Exit 程序正常终止, 但atexit(), at_quick_exit(), signal()登记的函数不被调用; 打开的流、文件是否被关闭,由编译器的实现者决定
}
输出结果:什么也没有
7 kill 函数发送信号
直接用kill函数给进程发送结束信号或是让程序自动退出。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc,char* argv[]){
pid_t pid;
int exit_code;
pid=getpid();//getpid()用来取得目前进程的进程识别码,许多程序利用取到的此值来建立临时文件,以避免临时文件相同带来的问题。
srand((unsigned)pid);
exit_code=(int)(rand() % 256);
sleep(10);/*本语句是:延时函数.延时10毫秒。sleep是阻塞线程函数,它会在当前语句阻塞一段时间,参数是以1/1000秒为单位的。执行sleep时当前线程放弃目前的时间片(在 10ms 内不会被再次调度),不参加资源的竞争,并且其他线程发送消息过来的时候,就没法响应,但同一程序的其它线程会照常工作。在DOS下,只有单线程,意味着死机。*/
if(atoi(*(argv+1)) % 2){//atoi(n)会扫描参数n字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时(‘\0’)才结束转换,并将结果返回。返回值:返回转换后的整型数。
printf("the child process id:%d receive signal SIGKILL\n",pid);
kill(pid,9);//编号为9的kill信号,强行“杀掉”该进程
}else{
printf("the child process id:%d normally exit,exit_code is %0x\n",pid,exit_code);
exit(exit_code);
}
}
程序执行结果:
Segmentation fault (core dumped)
下面程序通过fork函数创建子进程,并调用execl函数执行上面的程序。为了方便了解程序运行情况,在父进程中显示了创建的子进程的进程号。在while循环中调用wait函数,跳出条件是wait函数放回值小于0,或wait_pid为-1。这种情况下,所有的子进程都已经完全退出。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc,char* argv[]){
pid_t pid,wait_pid;
int status;
int i;
if(argc<4){
printf("Usage: %s para1 para2 para3\n",argv[0]);
return 1;
}
for(i=1;i<4;i++)
if((pid=fork())==0)
execl("./p7.14","p7.14",argv[i],NULL);//Excel函数即是预先定义,执行计算、分析等处理数据任务的特殊公式。
else
printf("create the child process id: %d\n",pid);
while((wait_pid=wait(&status)) && wait_pid!=-1)/*wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status 返回,而子进程的进程识别码也会一快返回。如果不在意结束状态值,则参数status 可以设成NULL。子进程的结束状态值请参考waitpid()。返回值如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno 中。*/
printf("process id:%d exit,exit_code is %0x\n",wait_pid,status);
return 0;
}
执行结果:Usage: ./kill-fork para1 para2 para3
8 waitpid函数
使用waitpid等待SIGSTOP,SIGCONT和SIGKILL这3种信号.
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
pid_t pid,wait_pid;
int status;
pid = fork();
if (pid==-1) {
perror("Cannot create new process");
exit(1);
}
else if (pid==0) {
printf("child process id: %ld\n", (long) getpid());
pause();
_exit(0);
}
else {
do {
wait_pid=waitpid(pid, &status, WUNTRACED | WCONTINUED);
if (wait_pid == -1) {
perror("cannot using waitpid function");
exit(1);
}
if (WIFEXITED(status))
printf("child process exites, status=%d\n", WEXITSTATUS(status));
if(WIFSIGNALED(status))
printf("child process is killed by signal %d\n", WTERMSIG(status));
if (WIFSTOPPED(status))
printf("child process is stopped by signal %d\n", WSTOPSIG(status));
if (WIFCONTINUED(status))
printf("child process resume running....\n");
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(0);
}
}
执行结果:
child process id: 3060
.....
一段时间后还是退不出来,最后强制关闭终端
9. 僵尸进程
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main (void)
{
pid_t pid;
pid = fork();
if(pid<0){
perror("cannot create new process");
exit(1);
}
if (pid>0)
sleep (60);
else
exit (0);
return 0;
}
执行结果:无任何显示.....一段时间后照常其他命令