Linux-进程

fork

    fork创建的新进程被称为子进程(child process),fork函数被调用一次,返回两次,子进程的返回值是0代表成功,而父进程的返回值则是子进程的进程 id。

    子进程完全拷贝父进程空间,共享代码空间,但数据空间是互相独立的,子进程数据空间中的内容是父进程的完整拷贝,指令指针也完全相同;子进程里面可以使用父进程的代码和变量,且内存地址相同,但是有自己的数据空间,其表现为对变量操作不影响父进程的值,是独立的。

    父进程先运行,但运行后的顺序是不确定的,如果涉及同步问题可以使用进程间通信机制解决。可使用sleep,wait等待子进程先运行。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

int gi = 0;

int main()
{
	int li = 0;
	static int si=0;

	pid_t pid = fork();
	if(0 == pid)
	{
		printf("child pid=%d,parent pid=%d\n", getpid(),getppid());
		gi += 1;
		li += 1;
		si += 1;
		printf("child process:%d - %d - %d\n", gi, li, si);//1 - 1 - 1
	}
	else if(0 < pid)
	{
		printf("child pid=%d\n", pid);
		sleep(1);//wait son process
		gi += 1;
		li += 1;
		si += 1;
		printf("parent process:%d - %d - %d\n", gi, li, si);//1 - 1 - 1
	}
	else
	{
		perror("fork failed,exit -1!");
		exit(-1);
	} 

	exit(0);
}

vfork

    vfork创建的子进程共享父进程的内存地址空间,即子进程完全运行在父进程的地址空间上,子进程对虚拟地址空间的修改同样为父进程所见,为了防止父进程重写子进程重要数据,阻塞父进程的执行,一直到子进程退出或执行一个新的程序为止。不能用sleep函数让父进程先运行。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int gi = 0;

int main()
{
	int li = 0;
	static int si=0;

	pid_t pid = vfork();
	if(0 > pid)
	{
		perror("fork");
	} 
	else if(0 == pid)
	{
		gi += 1;
		li += 1;
		si += 1;
		printf("child process:%d - %d - %d\n", gi, li, si);//1 - 1 - 1
	}
	else
	{
		gi += 1;
		li += 1;
		si += 1;
		printf("parent process:%d - %d - %d\n", gi, li, si);//2 - 2 - 2
	}

	exit (0);
}

exec函数族

    在进程中启动一个程序,成功不返回,失败返回-1。

#include <stdio.h>
#include <unistd.h>

int main()
{
	char *agv[] = {"ls", "-al", NULL};
	char *env[] = {"PATH=.", NULL};

	//if(0 > execl("/bin/ls", "ls", "-la", NULL))
	//if(0 > execv("/bin/ls", agv))
	//if(0 > execlp("ls", "-al", NULL))
	if(0 > execle("b.out", "b.out", NULL, env))
	{
		perror("exec*");
		return -1;
	}
}

system

     system会调用fork()产生子进程,由子进程来调用/bin/sh -c string来执行参数string字符串所代表的命令,命令执行完后随即返回原调用的进程。

    =-1:出现错误 
    = 0:调用成功但是没有出现子进程 
    > 0:成功退出的子进程的id 

#include <stdio.h>
#include <stdlib.h>

int main()
{
	int ret = system("ls -al");
	if(ret < 0)
		perror("system");
	else
		printf("ret=%d\n",ret);//ret=0
	return 0;
}

exit

    登记函数atexit,程序退出时调用的函数,int atexit (void (*)(void)),exit调⽤终⽌处理函数的顺序和atexit登记的顺序相反。

    _exit,直接使进程终止运行,清除其使用的空间,并销毁内核中各种数据结构。

    exit,在调用exit系统函数之前,检查打开文件,把文件缓冲区的内容写回文件,清理I/O缓冲,并调用登记函数。

#include <stdio.h>
#include <stdlib.h>

#include <unistd.h>

void e1(void)
{
	printf("-------1--------\n");
}
void e2(void)
{
	printf("-------2--------\n");
}

int main()
{
	if(0 > atexit(e2))
	{
		perror("atexit");
		return -1;
	}

	if(0 > atexit(e1))
	{
		perror("atexit");
		return -1;
	}

	printf("main code\n");
	int i = 0;
	i++;

	exit(-1);
	//_exit(-1);
}

    打印:

        main code
        -------1--------
        -------2--------

Daemon守护进程

    调用fork,创建子进程,而调用setsid函数之前,当前进程不允许是进程组的Leader,则需要将父进程退出;
    调用setsid函数创建一个会话;
    将当前工作目录更改为根目录其他目录;

    umask(0):调用umask将文件模式创建屏蔽字设置为0. 原因:又继承来的文件模式创建屏蔽字可能会拒绝设置某种权限,而守护进程需要创建的文件要具有读写权限。

    实例:创建守护进程a.out,在/tmp目录下创建文件demo.txt,每隔3秒写字符串"hello world\n"到文件。

#include <stdio.h>
#include <unistd.h>

int main()
{
	pid_t pid = fork();
	if(0 > pid)
	{
		perror("fork");
		exit(-1);
	}
	if(0 < pid)
	{
		exit(-1);//parent process exit
	}

	setsid();

	chdir("/tmp");

	umask(0);

	int fdsz = getdtablesize();
	int i = 0;
	for(i = 0; i < fdsz; i++)
		close(i); 

	while(1)
	{
		FILE *fp = fopen("demo.txt", "a");
		if(NULL == fp)
		{
			perror("fopen");
			exit(-1);
		}

		char buf[] = "hello world\n";

		int ret = fwrite(buf, sizeof(buf)-1, 1, fp);
		if(0 > ret)
		{
			perror("fwrite");
		}

		fclose(fp);

		sleep(3);
	}
}

猜你喜欢

转载自blog.csdn.net/TSZ0000/article/details/83071795