Linux系统编程:多任务编程2 + 线程
功能:等待子进程状态改变,但是这里我们研究的是子进程的退出参数:@wstatus:用来保存子进程退出的状态值的返回值会传给父进程,而父进程可以通过wait或waitpid的wstatus来获得注意要获得退出状态值需要使用宏才能获取WIFEXITED(wstatus)//判断子进程是否时正常结束WEXITSTATUS(wstatus)//获取子进程退出状态WIFSIGNALED(wstatus)//
目录
wait --> pid_t wait(int *wstatus); #include
waitpid --> pid_t waitpid(pid_t pid, int *wstatus, int options); #include #include
线程的创建 pthread_create (3)库函数 #include
wait --> pid_t wait(int *wstatus); #include <sys/wait.h>
功能:等待子进程状态改变,但是这里我们研究的是子进程的退出
参数:@wstatus:用来保存子进程退出的状态值的
返回值
- 成功返回 结束了的子进程的PID
- 失败返回 -1
注意:
- wait函数是一个阻塞操作,等当前进程的任意子进程结束
- wait一次只能处理一个子进程
会传给父进程,而父进程可以通过wait或waitpid的wstatus来获得
注意
要获得退出状态值需要使用宏才能获取WIFEXITED(wstatus)//判断子进程是否时正常结束WEXITSTATUS(wstatus)//获取子进程退出状态WIFSIGNALED(wstatus)//判断子进程是否是信号结束的WTERMSIG(wstatus)//获得结束的信号编号
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc,const char *argv[])
{
//(1) f
printf("test fork\n");
pid_t pid = fork();
if(pid < 0)
{
perror("fork fail");
return -1;
}
//(2) f and c
printf("main pid = %d\n",pid);
//(3) f
if(pid > 0)
{
while(1)
{
printf("f pid = %d\n", getpid());
sleep(1);
int wstatus;
if(wait(&wstatus) < 0) //回收资源
{
perror("wait fail");
return -1;
}
if(WIFEXITED(wstatus))
{
printf("child exit status = %d\n",WEXITSTATUS(wstatus));
}
}
}
//(4) c
else if(pid == 0)
{
int i = 0;
while(i < 5)
{
printf("c pid = %d\n",getpid());
sleep(1);
++i;
}
exit(99);
}
return 0;
}
在之前的代码中添加信号在只有父进程要做的事里面
if(WIFEXITED(wstatus))
{
printf("child exit status = %d\n",WEXITSTATUS(wstatus));
}
if(WIFSIGNALED(wstatus))
{
printf("child exit signal = %d\n",WTERMSIG(wstatus));
}
每个子进程退出时带出一个状态,父进程可以根据状态来判断是哪个子进程
waitpid --> pid_t waitpid(pid_t pid, int *wstatus, int options); #include <sys/types.h> #include <sys/wait.h>
功能:等待子进程状态改变(退出)
参数: @wstatus //用来保存 子进程退出的状态值的
返回值:
- 成功 返回结束了的子进程的pid
- 失败 返回-1
线程
线程 被称为 轻量级线程,之前我们学习的算重量级线程,轻量和重量主要在于资源的占用
创建进程和创建线程
- 进程 = PCB + |堆栈|bss|data|text|
- 线程 = 线程ID + 程序计数器|寄存器集合|栈

线程与进程的关系:
- 在线程出现以后,线程变成了CPU调度执行的最小单位(侧重于执行的单位),进程是资源分配的最小单位(侧重于资源分配的单位)
- 线程的创建和切换(调度)效率高于进程
- 线程依附于进程,线程是存在于进程的空间,进程不存在则线程也不存在;多个线程共享了进程资源,代码段,数据段,打开的文件等
在linux内核中,实际上是不区分进程和线程的,统一被称为任务--task,Linux为了支持线程编程 -- linux thread //thread编程
red hat -- 韩国 -- linux -- NPTL(线程库)
ibm -- 美国早计算机的公司

线程的创建 pthread_create (3)库函数 #include <pthread.h>
pthread_create --> int pthread_create(pthread_t *thread, //线程id
const pthread_attr_t *attr, //线程属性 NULL 默认属性
void *(*start_routine) (void *), // 线程回调函数(执行函数)
void *arg // arg );表示传递给线程执行
功能:创建线程
返回值:
- 成功 返回0
- 失败 返回错误码
注意:
- 使用线程库时,编译时记得要在gcc后面链接上 pthread 库 gcc thread.c -lpthread
- 线程创建好之后,此时有两个执行流,一个是主函数所在的执行流(主线程),一个是子线程所在的执行流(子线程/次线程)
- 在线程中,线程之间关系是对等
- 线程共享了进程资源:数据段,全局变量,局部变量,堆区变量,因为共享时如果使用的是同一个变量, 那么多个线程之间会有相互影响
- 线程创建好之后,线程的运行顺序也是不确定的 最终都需要由操作系统来调度
- 线程共享数据方便,如果是想让多线程相互影响同一个数据,那么传参的时候需要传地址做*运算,如果多线程使用同一个初值,但是各自操作各自,那么想办法获得值
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
void * do_sth(void *arg)
{
printf("do_sth\n");
}
int main(int argc,const char *argv[])
{
pthread_t tid;
int ret = pthread_create(&tid,NULL,do_sth,NULL);
if(ret != 0)
{
errno = ret; //errno 系统的一个全局变量,用来存放全局的错误码
perror("pthread_create error");
return -1;
}
printf("main \n");
sleep(3);
return 0;
}
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
void * do_sth1(void *arg)
{
int a = *(int *)arg;
while(1)
{
a++;
printf("a1 = %d\n",a);
sleep(1);
}
return NULL;
}
void * do_sth2(void *arg)
{
int a =*(int *)arg;
while(1)
{
a+=2;
printf("a2 = %d\n",a);
sleep(1);
}
return NULL;
}
int main(int argc,const char *argv[])
{
int a = 0;
pthread_t tid[2];
//1
int ret = pthread_create(&tid[0],NULL,do_sth1,&a);
if(ret != 0)
{
errno = ret; //errno 系统的一个全局变量,用来存放全局的错误码
perror("pthread_create error");
return -1;
}
//2
ret = pthread_create(&tid[1],NULL,do_sth2,&a);
if(ret != 0)
{
errno = ret; //errno 系统的一个全局变量,用来存放全局的错误码
perror("pthread_create error");
return -1;
}
// printf("main \n");
while(1)
sleep(1);
return 0;
}
更多推荐
所有评论(0)