Linux学习记录十四----------线程的创建和回收

文章目录


五、Linux线程

1.守护进程

守护进程是一种长期运行的进程(守护进程的生存期不一定长,但一般应该这样做),一般是操作系统启动的时候它就启动,操作系统关闭的时候它才关闭。守护进程跟终端无关联,也就是说它们没有控制终端,所以控制终端退出,也不会导致守护进程退出。守护进程是在后台运行的,不会占着终端,终端可以执行其他命令。Linux 操作系统本身是有很多的守护进程在默默地运行,维持着系统的日常活动。

1.1.守护进程的特点
  • 后台服务进程

  • 独立于控制终端

  • 周期性执行某任务

  • 不受用户登录注销影响

  • 一般采用以d结尾的名字(服务)

1.2.进程组
  • 进程的组长
    • 组里边的第一进程
    • 进程组的ID==进程中的组长的ID
  • 进程中组长的选择
    • 进程中的第一个进程
  • 进程组ID的设定
    • 进程组的ID就是组长的进程ID
1.3会话
  • 创建一个会话注意事项

    • 不能是进程组长
    • 创建会话的进程成为新进程组的组长
    • 有些lInux版本需要root权限执行此操作
    • 创建出的新会话会丢弃原有的控制终端 一般步骤;fork ,父亲死,儿子执行创建会话操作(setsid)
  • 获取进程所属的会话ID

    • pid_t getsid(pid_t pid);
  • 创建一个会话

    • pid_t setsid(void);
1.4创建守护进程模型
  • fork子进程,父进程退出 ----必须

  • 子进程创建新会话 -------必须

  • 改变当前工作目录chdir ---非必须

  • 重设文件掩码 --非必须

  • 关闭文件描述符 --非必须

  • 执行核心工作----必须

c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>


int main()
{
        pid_t pid;
        pid = fork();
        if(pid == 0)
        {
                pid_t sid;

                sid = setsid();//创建会话
           
                while(1){//执行核心工作
        			sleep(1);
        		}
        }
        else if(pid > 0)
        {
                exit(0);//父进程退出
        }
        return 0;
}

2.线程的概念

在Linux下: 线程就是进程-轻量级进程 对于内核来货,线程就是进程 多进程和多线程的区别:

多进程: 始终共享的资源 代码、文件描述符、内存映射区--mmap

多线程:始终共享的资源:堆、全局变量,节省资源

  • 主线程和子线程

    • 共享: .text .bss .data 堆 动态加载区 环境变量 命令行参数
  • 通信:全局变量,堆

  • 不共享栈

    • eg一共五个线程,栈区被平均分成五块
  • 查看指定线程的LWP号:

    • 线程号和线程ID是有区别的
      • 线程号是给内核看的
  • 查看方式

    • 找到程序的进程ID

      • ps -Lf pid
      • top -p tid(线程状态动态显示)

3.线程的创建及相关函数

3.1.创建线程‐‐pthread_create
c 复制代码
int pthread_create( pthread_t *thread), //线程ID = 无符号长整型
					const pthread_attr_t *attr, //线程属性,NULL
					void *(*start_routine)(void *), //线程处理函数
					void *arg); //线程处理函数
/*@param:
 *		pthread:传出参数,线程创建成功之后,会被设置一个合适的值
 *		attr:默认传NULL
 *		start_routine:子线程的处理函数
 *		arg: 回调函数的参数
 *@return:成功:0,错误:错误号 //perror不能使用该函数打印错误信息
 */
注意:
	主线程先退出,子线程会被强制结束
	验证线程直接共享全局变量

创建线程

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

int i = 0;

void * pthread_son(void *arg)
{
	
	printf("create pthread successed pthid is %ld\n",pthread_self());
	while(i++)
	{
		printf("i = %d\n",i);
		sleep(1);
	}

}

int main()
{
	pthread_t pthid;
	int ret;
	ret = pthread_create(&pthid,NULL,pthread_son,NULL);
	if(ret != 0)
	{
		printf("error num is %d\n",ret);
        printf("%s\n",strerror(ret));
		return -1;
	}
	printf("create pthread successed parent pthid is %ld\n",pthread_self());

	for(;i < 5;i++)
	{
		printf("i = %d\n",i);
	}
	sleep(3);
	return 0;
}
3.2.单个线程退出 --pthread_exit

不论是主线程还是子线程调用exit(0)后整个所以线程都会结束,而调用pthread_exit()只会退出当前进程

c 复制代码
函数原型: void pthread‐exit(void *retval);
retval指针:必须指向全局,堆
3.3.阻塞等待线程退出,获取线程退出状态--pthread_join
c 复制代码
函数原型:
int pthread_join(pthread_t pthread, void **retval)
/*参数:
 *		pthread:要回收的子线程的ID
 *		retval:读取线程退出的携带信息
 *	传出参数
 *		void* ptr;
 */
     	pthread_join(pthid,&ptr);
 		指向的内存和pthread_exit参数指向地址一致

单个线程退出并回收

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

int i = 0;
int num = 100;
void * pthread_son(void *arg)
{
	
	printf("create pthread successed pthid is %ld\n",pthread_self());
	while(i++)
	{
		printf("i = %d\n",i);
		sleep(1);
		if(i == 10)
		{
			printf("exit pthread_son\n");
			pthread_exit(&num);//退出子线程
		}
	}

}

int main()
{
	pthread_t pthid;
	int ret;
	ret = pthread_create(&pthid,NULL,pthread_son,NULL);
	if(ret != 0)
	{
		printf("error num is %d\n",ret);
        printf("%s\n",strerror(ret));
		return -1;
	}
	printf("create pthread successed parent pthid is %ld\n",pthread_self());

	for(;i < 5;i++)
	{
		printf("i = %d\n",i);
	}
	void *ptr;
	pthread_join(pthid,&ptr);//回收线程ID为pthid的子线程
	printf("join child pthread  num is %d\n",*(int *)ptr);
	return 0;
}
3.4.线程分离函数--pthread_detach
c 复制代码
函数原型:int pthread_datach(pthread_t thread);
调用该函数之后不需要 pthread_join
子线程会自动回收自己的PCB
3.5.杀死(取消)线程--pthread_cancel
c 复制代码
函数原型: int pthread_cancel(pthread_t pthread);

pthread_testcancel();设置取消点---在取消点时就会杀死该线程

注:

  • 使用注意事项:

    • 在要杀死的子线程对应的处理的函数的内部,必须做过一次系统调用 (阻塞调用)
    • write read printf
    • int a = 2; int b = a+3;
    • 否则需要手动设置取消点
    c 复制代码
    int pthread_setcanceltype(int type,int *oldtype)
    PTHREAD_CANCEL_DEFERRED//等待目标点才会取消
    PTHREAD------CANCEL_ASYNCHRONOUS//目标线程会立即取消
3.6.比较两个线程ID是否相等(预留函数) --pthread_equal
c 复制代码
函数原型:
int pthread_equal(pthread_t t1,pthread_t t2);

4.线程的分离属性

如果不回收线程资源会造成内存泄漏,且join不能完全回收线程资源

通过属性设置线程的分离

1.线程属性类型: pthread_attr_t attr;

2.线程属性操作函数:

  • 对线程属性变量的初始化
    • int pthread_attr_init(pthread_attr_t* attr);
  • 设置线程分离属性
    • int pthread_attr_setdetachstate( pthread_attr_t* attr, int detachstate );
    • 参数:
      • attr : 线程属性
      • detachstate PTHREAD_CREATE_DETACHED(分离) PTHREAD_CREATE_JOINABLE(非分离)
  • 释放线程资源函数 int pthread_attr_destroy(pthread_attr_t* attr);

设置分离属性

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

int i = 0;
int num = 100;
void * pthread_son(void *arg)
{
	
	printf("create pthread successed pthid is %ld\n",pthread_self());
	while(i++)
	{
		printf("i = %d\n",i);
		sleep(1);
		if(i == 10)
		{
			printf("exit pthread_son\n");
			pthread_exit(&num);
		}
	}

}

int main()
{
	pthread_t pthid;
	int ret;
	pthread_attr_t attr;
	pthread_attr_init(&attr);//初始化线程属性变量
	pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//设置线程属性
	ret = pthread_create(&pthid,&attr,pthread_son,NULL);
	if(ret != 0)
	{
		printf("error num is %d\n",ret);
        printf("%s\n",strerror(ret));
		return -1;
	}
	printf("create pthread successed parent pthid is %ld\n",pthread_self());

	for(;i < 5;i++)
	{
		printf("i = %d\n",i);
	}
	sleep(15);
	pthread_attr_destroy(&attr);//释放线程资源函数
	return 0;
}
相关推荐
o(╥﹏╥)6 分钟前
在 Ubuntu 上安装 VS Code
linux·运维·vscode·ubuntu·vs
奶香臭豆腐26 分钟前
C++ —— 模板类具体化
开发语言·c++·学习
不爱学英文的码字机器33 分钟前
[Linux] Shell 命令及运行原理
linux·运维·服务器
cdut_suye44 分钟前
Linux工具使用指南:从apt管理、gcc编译到makefile构建与gdb调试
java·linux·运维·服务器·c++·人工智能·python
qq_433618441 小时前
shell 编程(三)
linux·运维·服务器
波音彬要多做1 小时前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
Tlzns1 小时前
Linux网络——UDP的运用
linux·网络·udp
码农土豆1 小时前
PaddlePaddle飞桨Linux系统Docker版安装
linux·docker·paddlepaddle
Noah_aa1 小时前
代码随想录算法训练营第五十六天 | 图 | 拓扑排序(BFS)
数据结构
Hacker_xingchen1 小时前
天融信Linux系统安全问题
linux·运维·系统安全