Linux多线程编程—进程

Linux多线程编程—进程

一.进程

  1. 含义:装载程序运行的载体 正在运行的程序 动态的 进程分配资源的最小单位
  2. 进程标识 PID(Process ID) init 1
  3. 查看进程
    ps aux 查看所有用户的所有进程信息
    pstree 查看进程树
    top 动态查看进程
  4. 进程状态
    就绪态
    执行态
    阻塞态
  5. 父:fork–
    子 exec(任务)
    死 --exit (int)
    wait()
  6. 孤儿进程:父进程消亡 子进程没有消亡 子进程就是孤儿进程 init领养并收尸
    僵尸进程:子进程消亡 父进程没有消亡 但却不为子进程收尸 子进程是僵尸进程 僵尸进程会造成资源浪费 避免僵尸进程
  7. 进程PID
    #include <sys/types.h>
    #include <unistd.h>
    (1) pid_t getpid(void);
    功能:获取当前调用进程PID
	   #include<stdio.h>
	   #include<unistd.h>
	   #include<sys/types.h>
	   int main()
	   {
			printf("%d\n",getpid());
	   }
(2)  pid_t getppid(void); 	
功能:获取当前调用进程的父进程PID
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
	printf("child:%d   par:%d\n",getpid(),getppid());
}
  1. 创建进程
    #include <unistd.h>
    pid_t fork(void);
    功能:创建子进程
    成功返回值:返回两次
    父进程中:返回子进程PID
    子进程中:返回0
    失败返回-1
    1)代码
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
	fork();
	printf("child:%d   par:%d\n",getpid(),getppid());//printf会执行两次 说明有两个进程调用printf
}
  1. 如何区分父子进程
int main()
{
	pid_t pid = fork();
	if(pid<0)
	{
		perror("fork");
	}
	else if(pid>0)
	{
		printf("father:%d ",getpid());	
	}
	else 
	{
		printf("child:%d ",getpid());
	}
}

注意:父子进程执行的先后顺序不确定 取决于系统调度策略
sleep控制父子进程执行顺序
练习1:实现父进程打印"par is running …" 子进程打印"child is running "
间隔1s

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
	pid_t pid = fork();
	if(pid<0)
	{
		perror("fork");
	}
	else if(pid>0)//父亲
	{
		sleep(1);//保证子先运行
		while(1)
		{
			printf("father:%d\n",getpid());
			sleep(1);
		}
	}
	else //子
	{
		while(1)
		{
			printf("child:%d\n",getpid());
			sleep(1);
		}
	}

}

练习2:父进程中有一个变量count=0 创建子进程后 子进程count++
打印父进程的count和子进程count
3) 循环创建多进程

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{

	int i;
	for(i=0;i<3;i++)
	{
		fork();
		printf("pid:%d ppid:%d\n",getpid(),getppid());
	}
	
}

i=0 父 子1
i=1 子2 子1-1
i=2 子3 子1-2 子2-1 子1-1-1

4)进程消亡
(1)#include <stdlib.h>
   void exit(int status);
  功能:退出进程 会刷新IO缓存
(2)#include <unistd.h>
   void _exit(int status);
功能:立即退出进程 不会刷新IO缓存

#include<stdio.h>
#include<unistd.h>
int fun()
{
	//return 0;//返回到调用者
	printf("day day up");
	//exit(-1);//退出进程
	_exit(-1);
}
int main()
{
	fun();·
	puts("************");
}

5)进程收尸
#include <sys/types.h>
#include <sys/wait.h>
(1)pid_t wait(int *status);
功能:等待一个子进程结束 取得子进程结束的状态 将其保存在status中
返回值:返回被收尸的子进程PID 如果没有子进程返回-1

注意: 
a、父进程调用wait时 父进程会阻塞等待子进程结束
b、如果父进程不关心子进程退出的状态  wait参数可以传NULL
c、wait后 子进程占用的资源会被释放
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
	int count=10;
	pid_t pid = fork();
	if(pid<0)
	{
		perror("fork");
	}
	else if(pid>0)//父
	{
		pid_t waitpid = wait(NULL);
		printf("father-waitpid:%d pid:%d\n",waitpid,pid);	
	}
	else //子
	{
		sleep(1);
		printf("child:%d\n",getpid());
	}
}

(2) waitpid
pid_t waitpid(pid_t pid, int *status, int options);
功能:同wait
参数1:
-1 等待任意子进程收尸
>0 为进程编号为pid的子进程收尸
参数2:同wait
参数3:
WNOHANG 没有子进程消亡则不阻塞等待
0 阻塞等待子进程消亡

返回值:
成功收尸返回被收尸的子进程PID 没有字进程消亡返回0 失败-1

 #include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
	int count=10;
	pid_t pid = fork();
	if(pid<0)
	{
		perror("fork");
	}
	else if(pid>0)//父
	{
		//pid_t wait_pid = waitpid(-1,NULL,0);
		pid_t wait_pid = waitpid(-1,NULL,WNOHANG);
		printf("father-waitpid:%d pid:%d\n",wait_pid,pid);	
	}
	else //子
	{
		sleep(1);
		printf("child:%d\n",getpid());
	}
}   

6)进程执行任务
exec族函数:在本进程中加载另一个程序 并且从头开始执行 本进程完全由新程序替换
(1)int execl(const char *path, const char *arg, …);
格式:execl(可执行程序的路径,可执行程序的名称,参数1,参数2,参数3,…,NULL);
注意:可执行文件路径 必须是which结果 which ls

#include<unistd.h>
int main()
{
	puts("come-------------------");
	execl("/bin/ls","ls","-i",NULL);
	puts("bye----------------------");//不会输出 因为加载完新程序 原来程序会被替换
}

练习:创建一个文件

#include<unistd.h>
int main()
{
	puts("come-------------------");
	//execl("/bin/ls","ls","-i",NULL);
	execl("/usr/bin/touch","touch","happy.txt",NULL);	
	puts("bye----------------------");
}

(2)int execvp(const char *file, char *const argv[]);
格式:execvp(可执行文件名,指针数组)

#include<unistd.h>
int main()
{
	puts("come-------------------");
	//execl("/bin/ls","ls","-i",NULL);
	char *cmd[]={"ls","-i",NULL};
	execvp("ls",cmd);
	puts("bye----------------------");
}
 #include<unistd.h>
int main()
{
	puts("come-------------------");
	//execl("/bin/ls","ls","-i",NULL);
	char *cmd[]={"touch","smile",NULL};
	execvp("touch",cmd);
	puts("bye----------------------");
} 

//str.c

#include<stdio.h>

int main()
{
	puts("aaa----");
}

//exec.c

#include<unistd.h>
int main()
{
	execl("./str","str",NULL);
}

练习: 编程实现 执行ls -l 执行完毕后 打印finished
子进程 ls -l
父 收尸并打印

#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
int main()
{
	pid_t pid = fork();
	if(pid<0)
	{
		perror("fork");
	}
	else if(pid>0)
	{
		wait(NULL);
		puts("finished!");
	}
	else 
	{
		execl("/bin/ls","ls","-l",NULL);
	}
}
  1. 守护进程编写
    前台进程:依附终端 终端结束 进程结束
    后台进程:不依附终端 自己独立存在
    进程组:多个进程
    会话:多个进程组
    1.创建子进程 父进程结束(init领养子进程)
    2.创建新会话 setsid()
    3.改变当前工作目录
    chdir("/tmp")
    4.修改文件掩码
    掩码:掩掉权限
    umask(0)
    5.关闭所有打开的文件描述符
    int getdtablesize(void);//获取当前进程打开的文件总个数
int n=getdtablesize();
	for(i=0;i<n;i++)
	{
		close(i);	
	}		

文件描述符分配规则:
当前尚未分配最小非负 0 1 2 3 4 5

#include<time.h>
#include<stdio.h>
int main()
{
	time_t t = time(NULL);
	printf("%s",ctime(&t));

}
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<time.h>
#include<stdlib.h>
void init_daemon()
{
	pid_t pid = fork();
	if(pid>0)
	{
		exit(0);
	}
	setsid();
	chdir("/tmp");
	umask(0);
	int n = getdtablesize();
	int i;
	for(i=0;i<n;i++)
	{
		close(i);
	}
}
int main()
{
	init_daemon();//创建守护进程
	
	FILE *fp=NULL;
	time_t t;
	while(1)
	{
		fp = fopen("time.log","a");
		if(fp!=NULL)
		{
			t = time(NULL);
			fprintf(fp,"%s",ctime(&t));	
			fclose(fp);
			sleep(1);
		}
	}	
}

练习:编写一个守护进程 每隔1s向文件中写入一个字母 字母从’a’开始 ‘a’~‘z’

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<time.h>
#include<stdlib.h>
void init_daemon()
{
	pid_t pid = fork();
	if(pid>0)
	{
		exit(0);
	}
	setsid();
	chdir("/tmp");
	umask(0);
	int n = getdtablesize();
	int i;
	for(i=0;i<n;i++)
	{
		close(i);
	}
}
int main()
{
	init_daemon();//创建守护进程
	
	FILE *fp=NULL;
	time_t t;
	char ch='a';
	while(1)
	{
		fp = fopen("char.txt","a");
		if(fp!=NULL)
		{
			t = time(NULL);
			fprintf(fp,"%c",ch);	
			fclose(fp);
			if(ch=='z')
			{
				ch='a';
				continue;
			}
			ch++;
			sleep(1);
		}
	}		
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值