9、作业:创建3个进程,子进1程拷贝文件的前一半,子进程2拷贝后一半文件,父进程回收两个子进程资源。
#include <myhead.h>
int main(int argc, const char *argv[])
{
int fd1,fd2,fd3;
pid_t pid1 = fork();
if(pid1 == 0) //子程序1
{
fd1 = open("./1.txt",O_RDONLY); //只读打开文件
if(fd1 == -1)
{
perror("open");
return -1;
}
fd2 = open("./2.txt",O_CREAT|O_TRUNC|O_WRONLY,0664); //创建只写清空文件
if(fd2 == -1)
{
perror("open");
return -1;
}
//计算长度
int len = lseek(fd1,0,SEEK_END);
lseek(fd1,0,SEEK_SET); //把光标置位到开头
char buff[1024]; //零时变量
int res = 0; //读取每次的长度
int len1 = 0; //子程序1的取的长度
while((len1+res)<len/2) //循环条件
{
res = read(fd1,buff,sizeof(buff)); //读取文件
len1 +=res; //累加长度
write(fd2,buff,res); //写入文件2.txt
}
//处理剩余部分
if((len1+res)<len)
{
res = read(fd1,buff,len/2-len1);
write(fd2,buff,res);
}
printf("子程序1拷贝完成\n");
close(fd1);
close(fd2);
}
else if(pid1 > 0) //父程序
{
pid_t pid2 = fork();
if(pid2 == 0) //子程序2
{
fd1 = open("./1.txt",O_RDONLY); //只读打开文件
if(fd1 == -1)
{
perror("open");
return -1;
}
fd3 = open("./3.txt",O_CREAT|O_TRUNC|O_WRONLY,0664); //创建只写清空文件
if(fd3 == -1)
{
perror("open");
return -1;
}
//计算长度
int len = lseek(fd1,0,SEEK_END);
lseek(fd1,len/2,SEEK_SET); //把光标置位到中间
char buff[1024]; //临时变量
int res; //读取每次的长度
int len1 = 0; //子程序1的取的长度
while(res = read(fd1,buff,sizeof(buff))) //读取文件
{
write(fd3,buff,res); //写入文件3.txt
}
printf("子程序2拷贝完成\n");
close(fd1);
close(fd3);
}
//回收资源
waitpid(pid1,NULL,0);
waitpid(pid2,NULL,0);
}
else
{
perror("fork");
return -1;
}
return 0;
}
wait和waitpid函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
功能:阻塞回收子进程的资源。
参数:子进程退出时的状态
返回值:成功回收子进程资源后返回子进程的ID,失败时返回-1.
pid_t waitpid(pid_t pid, int *wstatus, int options);
功能:阻塞或者非阻塞回收子进程资源
参数1: >0:回收特定某个子进程资源
=0:回收当前进程组的所有子进程资源
=-1:回收任意的子进程资源
<-1:回收进程组ID等于pid绝对值的所有子进程资源.
参数2:接收进程退出时的状态一般不接收。
参数3: 0:阻塞回收子进程的资源
WNOHANG:非阻塞回收子进程资源.
返回值:成功返回回收的进程ID,失败返回-1,但是如果参数3是WNOHANG 成功后返回0。
4、验证进程的多任务并发执行
5、验证孤儿进程和僵尸进程
子进程退出后子进程修改的数据是否保存
7、创建守护进程
1、创建一个孤儿进程,并修改孤儿进程的操作目录权限为根目录(对根目录某个文件具有读写权限)。
2、将孤儿进程设置为会话组组长,脱离终端独立运行(该孤儿进程变成守护进程)。
3、更改终端下的umask值,以便于创建的文件具有读写执行的全部权限。
4、在根目录下创建一个日志文件。
5、重定向所有的输入输出出错描述符到该日志文件。
#include <sys/types.h>
#include <unistd.h>
pid_t setsid(void);
功能:设置调用进程为会话组组长。
参数:无
返回值:成功返回会话组组长的(新的)ID失败返回-1,并置位错误码。
#include <unistd.h>i
int chdir(const char *path);
功能:修改调用进程的工作目录。
参数:要更改的工作目录
返回值:成功返回0,失败返回-1,并置位错误码。
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask);
功能:更改某个目录下的umask值
参数:要更改的umask值
返回值:成功返回旧的umask值,没有失败可言。
创建守护进程
验证如何创建3个进程
线程概念
1、线程是轻量化的进程,一个进程内可以有多个线程,至少包含一个线程(主线程)。
2、线程的任务调度,创建,销毁的开销都要比进程小。
3、进程之间不共享资源,进程运行空间都是独立的,但是线程共享临界资源。
4、线程是任务调度的最小单位,进程是资源分配的最小单位。
5、多任务并发执行大多数选择多线程,而不是多进程,因为线程占用内存非常少大概8K。
6、多个线程每一个都有自己的id号。
7、线程函数来自于第三方库,-pthread,所以要编译线程库函数需要加上 -pthread
8、多线程编程时,对于临界资源访问时可能有多个线程同时访问,这样会产生数据的错乱,这种现象被称为竞态。
pthread_create函数
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
功能:创建子线程的函数
参数1:存储创建的子线程号
参数2:创建时附加的线程属性,默认填NULL
参数3:函数指针,子线程的线程体函数,也是子线程开始运行的地方。
参数4:是线程体函数的参数,如果没有参数填NULL即可。
返回值:成功返回0,失败返回-1,并且线程号不确定。
思维导图
线程基础