linux~~监控子进程&创建新的线程

目录

1.wait函数介绍

2.wait函数演示

3.pthread_create函数介绍

3.1总体介绍

3.2参数介绍

3.3返回值说明

3.4进程线程关系演示

4.pthread_join函数

5.pthread_create函数第四个参数

6.创建两个线程

6.1创建方法

6.2线程进程对比


1.wait函数介绍

  • wststus参数,输出类型的参数,进程的状态改变的原因的相关信息,如果我们不关心这个子进程为什么状态发生了改变,我们就可以把这个参数设置为nullptr;
  • 终止的子进程的pid号码作为这个wait函数的返回值;
  • wait等待任意的一个子进程终止退出,如果子进程都不结束,wait将会一直处于一个阻塞的状态,有一个子进程终止,这个函数就会有对应的终止进程的返回值;
  • 所有子进程全部终止结束,这个时候的wait函数的返回值就是-1;

2.wait函数演示

创建3个子进程,分别是5,10,15s之后结束,查看这个父进程等待的情况以及wait函数的返回值的情况;

下面将会通过代码实现这个过程:我们创建一个已知的进程,我们可以称之为父进程,这个父进程创建了三个子进程,分别给这三个子进程创建休眠的时间,5s,10s,15s等等;

这个时候的main函数里面设置了相关的参数,其中这个里面的第一个参数就是argc,这个参数的意义就是我们的main函数里面的参数的个数,第二个argv实际上就是我们的参数序列或者是指针,可以下去自行了解;

我们的这个for循环里面主要就是创建子进程(fork函数),打印这个子进程的id(getpid函数)和休眠时间,因为这个终端输出的是字符10,5,15,因此我们设置的休眠时间的时候需要使用这个atoi函数把这个字符转换为int类型的数据;

因为是3个子进程,但是这个下标是0,1,2,3,其中这个里面的0表示的就是我们的父进程,1,2,3分别表示的就是3个子进程,因此我们的这个for循环是从这个1开始循环的,当返回值是-1的时候,就说明这三个子进程全部结束了;

其中这个里面的while循环会一直进行,返回值-1这个子进程全部结束,我们打印输出一句话进行说明,同时记录下来这个子进程结束的个数,当返回值-1的时候在,合格循环就执行exit异常退出

运行输出结果:以及我们的输入的相关的要求,我们需要输出我们的这个子进程运行的时间,这个里面就是./a.out就是我们编译之后生成的可执行程序,10,5,15就是子进程的休眠时间,这个就是对应的我们的这个main函数里面的参数;

3.pthread_create函数介绍

3.1总体介绍

这个函数就是线程的创建函数,线程是有进程创建出来的,线程的资源都来自于创建线程的进程;

我们使用gcc进行编译和连接的时候需要使用-pthread选项,告诉编译器这个函数在哪个位置,这个compile和link就是编译和连接的意思;

3.2参数介绍

这个里面的第三个参数的意义就是我们的函数指针,这个指针的指向的地址存储的就是我们的这个线程需要执行的内容,这个函数指针的返回值就是void*类型的,函数指针的参数就是void*类型的

第四个参数是传递给线程的参数,如果我们没有给这个线程传递任何的参数,我们直接把第四个参数设置为空指针就可以了;

第一个参数是一个输出类型的参数,运行完这个线程之后会把这个线程的id号放到这个参数里面去,不需要我们人为设置;

第二个参数attr是一个结构体类型的指针,决定我们创建新的线程的属性,这个线程的属性,我们就放到这个结构体的属性,我们使用默认属性的话直接使用null这个默认的属性即可;

3.3返回值说明

正常的返回值就是0,如果返回值是一个非0数值,就说明这个函数执行过程出现错误;

3.4进程线程关系演示

进程结束,操作系统就会回收所有的资源和空间,线程依赖于进程,这个时候线程就不可以继续运行了;

下面的这个代码就是对于这个用法进行了说明,我们调用这个pthread_create函数创建一个新的线程,这个函数的参数就是我们上面介绍的,其中这个里面的第一个参数就是一个输出型的参数,只需要把我们自己定义的这个线程的地址传递过去就可以了;

第三个参数是一个函数指针,这个函数指针就是我们的函数名,因为在函数指针里面,函数名就是地址,第二个参数就是线程的属性,这个我们如果不需要的话就写作空指针即可,第四个参数是传递给线程的参数,我们后面会讲到(第五个部分会使用到),现在我们只用一下这个第一个和第三个参数,如果返回值是0,说明是正常的,不是0的话,我们就需要使用这个perror打印输出错误的原因;

我们的打印结果应该是10次的hello world,但是因为这个进程创建的线程,我们的进程里面的while会让这个线程一直打印,打印10次之后,这个线程就会退出,但是这个进程不会退出,这个进程就无法知道这个线程什么时候结束的;

但是如果我们不写这个while(1)因为这个进程就会直接return 0了,这个时候进程系统资源被回收,我们的这个线程就是进程创建的,因此这个时候的线程就不会输出这个打印的结果;

下面我们会介绍这个pthread_join函数解决这个问题:

4.pthread_join函数

这个函数第一个参数就是我们的的线程的名字,第二个参数就是一个指针变量,如果这个线程结束了之后,这个时候的pthread_join函数就会返回0,相当于告诉我们的进程,我们的线程已经结束了

第一个参数表示的就是我们等待哪一个进程结束,第二个参数保存的是线程的退出状态,不需要等待就是null指针;下面的这个代码里面,就是解决上面的那个while(1)的遗留问题的;

5.pthread_create函数第四个参数

第四个参数就是我们的进程传递给线程的参数,我们应该如何使用呢;例如还是这个循环打印10次hello world的语句,我们可以让这个第四个参数是ret=10的地址,这样的话这个10就可以传递给我们的函数指针的参数了,也就是我们的arg参数,这个时候的arg参数就是10,我们如何使用这个arg控制我们的循环呢?

这个时候就是首先要进行这个指针的解引用,但是因为这个原来的参数agr是一个void*类型的,解引用之后就是void类型的,并不是我们想要的整形int,因此这个时候我们需要进行强制类型的转换,然后这个循环就可以使用ret控制次数了,这个时候的pthread_create函数得第四个参数的作用就凸显了出来;

6.创建两个线程

6.1创建方法

其实两个线程的创建并不是很复杂,我们只需要按照上面的,调用两次这个pthread_create函数即可,然后创建两个线程分别的join函数,其他的都是一样的;

java 复制代码
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void *thread1_function(void *arg);
void *thread2_function(void *arg);

int count = 0;

int main(void)
{
	pthread_t pthread1, pthread2;
	int ret;

	ret = pthread_create(&pthread1, NULL, thread1_function, NULL);
	if(ret != 0)
	{
		perror("pthread_create");
		exit(1);
	}

	ret = pthread_create(&pthread2, NULL, thread2_function, NULL);
	if(ret != 0)
	{
		perror("pthread_create");
		exit(1);
	}

	pthread_join(pthread1, NULL);
	pthread_join(pthread2, NULL);
	printf("The thread is over, process is over too.\n");

	return 0;
}

void *thread1_function(void *arg)
{
	printf("Thread1 begins running\n");

	while(1)
	{
		printf("Thread1 count = %d\n", count++);
		sleep(1);
	}
	return NULL;
}

void *thread2_function(void *arg)
{
	printf("Thread2 begins running\n");
	while(1)
	{
		printf("Thread2 count = %d\n", count++);
		sleep(1);
	}
	return NULL;
}

6.2线程进程对比

我们上面的这个过程也可以说明一个问题:

因为这个多个线程是并发执行的,就是同一个变量,两个线程之间是可以相互看到的,但是对于两个进程而言,如果也是同一个变量,两个进程之间是相互独立的,一个进程对于另外一个进程没有影响,但是两个线程之间就不是独立的,他们可以共用一块空间,不然这个变量的数值怎么会连续增加呢?

因此,我们也可以看出来,这个线程之间想要保持通信其实并不难,因为他们的空间是一样的,但是对于进程而言,因为进程运行具有独立性,因此这个进程之间想要保持独立性,就没有线程之间那么简单!

相关推荐
woshilys7 分钟前
sql server 查询对象的修改时间
运维·数据库·sqlserver
疯狂飙车的蜗牛37 分钟前
从零玩转CanMV-K230(4)-小核Linux驱动开发参考
linux·运维·驱动开发
恩爸编程2 小时前
探索 Nginx:Web 世界的幕后英雄
运维·nginx·nginx反向代理·nginx是什么·nginx静态资源服务器·nginx服务器·nginx解决哪些问题
Michaelwubo3 小时前
Docker dockerfile镜像编码 centos7
运维·docker·容器
远游客07133 小时前
centos stream 8下载安装遇到的坑
linux·服务器·centos
马甲是掉不了一点的<.<3 小时前
本地电脑使用命令行上传文件至远程服务器
linux·scp·cmd·远程文件上传
jingyu飞鸟3 小时前
centos-stream9系统安装docker
linux·docker·centos
好像是个likun3 小时前
使用docker拉取镜像很慢或者总是超时的问题
运维·docker·容器
超爱吃士力架3 小时前
邀请逻辑
java·linux·后端
LIKEYYLL5 小时前
GNU Octave:特性、使用案例、工具箱、环境与界面
服务器·gnu