线程的创建与回收

目录

一、线程的创建

进程:

线程:

线程特点:

 一个进程中的多个线程共享以下资源:

 每个线程私有的资源包括:

 Linux线程库:

 线程创建-pthread_create

二、线程的参数传递

线程结束-pthread_exit

线程查看tid函数

三、线程的回收

线程回收-pthread_join:

线程分离pthread_detach:

四、线程回收内存演示


一、线程的创建

进程:

  • 进程有独立的地址空间
  • Linux为每个进程创建task_struct
  • 每个进程都参与内核调度,互不影响

线程:

  • 进程在切换时系统开销大
  • 很多操作系统引入了轻量级进程LWP
  • 同一进程中的线程共享相同地址空间
  • Linux不区分进程、线程

线程特点:

  • 通常线程指的是共享相同地址空间的多个任务
  • 使用多线程的好处
  1. 大大提高了任务切换的效率
  2. 避免了额外的TLB&cache的刷新

 

 一个进程中的多个线程共享以下资源:

  • 可执行的指令
  • 静态数据
  • 进程中打开的文件描述符
  • 当前工作目录
  • 用户PID
  • 用户组ID

 每个线程私有的资源包括:

  • 线程ID(TID)
  • PC(程序计数器)和相关寄存器
  • 堆栈
  • 错误号(errno)
  • 优先级
  • 执行状态和属性

 Linux线程库:

  • pthread线程库中提供了如下基本操作
  1. 创建线程
  2. 回收线程
  3. 结束线程
  • 同步和互斥机制
  1. 信号量
  2. 互斥锁

 Linux线程不是通过内核实现的,而是通过pthread线程库实现的。 

线程创建-pthread_create

#include <pthread.h>
int pthread_create(pthread_t *thread,constpthread_attr_t *attr,void *(*routine)(void *),void *arg);

成功返回0,失败时返回错误码

thread:线程对象

attr:线程属性,NULL代表默认属性

routine:线程执行的函数

arg:传递给routine的参数,参数是void *,注意传递参数格式

pthread_t pthread_self(void)        查看自己的TID

示例代码:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>int *testThread(char *arg)
{printf("This is a thread\n");return NULL;
}
int main()
{pthread_t tid;int ret;ret = pthread_create(&tid,NULL,(void *)testThread,NULL); //testThread强制返回void *printf("This is main thread\n");sleep(1);
}

 编译:

gcc creatP_t.c -lpthread

结果:

 

常见错误:

creatP_t.c: In function ‘main’:
creatP_t.c:14:36: warning: passing argument 3 of ‘pthread_create’ from incompatible pointer type [-Wincompatible-pointer-types]
     ret = pthread_create(&tid,NULL,testThread,NULL);
                                    ^
In file included from creatP_t.c:1:0:
/usr/include/pthread.h:233:12: note: expected ‘void * (*)(void *)’ but argument is of type ‘int * (*)(char *)’

解决方法:

 ret = pthread_create(&tid,NULL,(void *)testThread,NULL); //testThread强制返回void *

注意:

  • 主进程的退出,它创建的线程也会推出
  • 线程创建需要时间,如果主进程马上退出,那线程不能得到执行

二、线程的参数传递

 线程结束-pthread_exit

#include <pthread.h>
void pthread_exit(void *retval);
  • 结束当前线程
  • retval可被其他线程通过pthread_join获取
  • 线程私有资源被释放

线程查看tid函数

#include <pthread.h>
pthread_t pthread_self(void);

示例代码:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>int *testThread(char *arg)
{printf("This is a thread, pit = %d, tid = %lu\n",getpid(),pthread_self());pthread_exit(NULL);printf("after exit\n");//return NULL;
}
int main()
{pthread_t tid;int ret;ret = pthread_create(&tid,NULL,(void *)testThread,NULL); //testThread强制返回void *printf("This is main thread, tid = %lu\n",tid);sleep(1);
}

运行结果:

获取线程id两种方法:

  1. 通过pthread_create函数的第一个参数;
  2. 通过在线程里面调用pthread_self函数

 参数传递pthread_create:

pthread_create(pthread_t *thread,constpthread_attr_t *attr,void *(*routine)(void *),void *arg);

最后一个参数。

示例代码:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>void *testThread(void *arg)
{printf("This is a thread, pit = %d, tid = %lu\n",getpid(),pthread_self());printf("input arg = %d\n",*(int *)arg);//先将arg参数转换为int *指针类型,再通过*进行解引用pthread_exit(NULL);printf("after exit\n");//return NULL;
}
int main()
{pthread_t tid;int ret;int arg = 5;ret = pthread_create(&tid,NULL,testThread,(void *)&arg); //testThread强制返回void *printf("This is main thread, tid = %lu\n",tid);sleep(1);
}

运行结果:

注意:void *不能直接进行* arg,要强制类型转换为*(int *)arg ,否则会产生如下错误:

值传递代码示例:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>void *testThread(void *arg)
{printf("This is a thread, pit = %d, tid = %lu\n",getpid(),pthread_self());printf("input arg = %d\n",(int)arg);//先将arg参数转换为int *指针类型,再通过*进行解引用pthread_exit(NULL);printf("after exit\n");//return NULL;
}
int main()
{pthread_t tid;int ret;int arg = 5;ret = pthread_create(&tid,NULL,testThread,(void *)arg); //此时arg表示指针指向的一个值printf("This is main thread, tid = %lu\n",tid);sleep(1);
}

编译会出现警告,但是不影响参数传递:

运行结果:

 

参数传递注意:

  1. 通过地址传递参数,注意类型的转换
  2. 值传递,这时候编译器会告警,需要程序员自己保证数据长度正确

 创建多个线程代码示例:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>void *testThread(void *arg)
{printf("This is a thread, pit = %d, tid = %lu\n",getpid(),pthread_self());printf("input arg = %d\n",(int)arg);//先将arg参数转换为int *指针类型,再通过*进行解引用pthread_exit(NULL);printf("after exit\n");//return NULL;
}
int main()
{pthread_t tid[5];int ret;int arg = 5;int i;for(i = 0; i < 5; i++){ret = pthread_create(&tid[i],NULL,testThread,(void *)i); //testThread强制返回void *printf("This is main thread, tid = %lu\n",tid[i]);}sleep(1);
}

运行结果:

注意:

若出现以下运行错误, 

原因:栈被破坏了(数组越界) 

三、线程的回收

运行代码实例:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>void *testThread(void *arg)
{printf("This is a thread, pit = %d, tid = %lu\n",getpid(),pthread_self());printf("input arg = %d\n",(int)arg);//先将arg参数转换为int *指针类型,再通过*进行解引用//pthread_exit(NULL);while (1){sleep(1);}printf("after exit\n");//return NULL;
}
int main()
{pthread_t tid[5];int ret;int arg = 5;int i;for(i = 0; i < 5; i++){ret = pthread_create(&tid[i],NULL,testThread,(void *)i); //testThread强制返回void *printf("This is main thread, tid = %lu\n",tid[i]);}while (1){sleep(1);}
}

用命令查看进程信息:

用命令查看线程信息:

 线程回收-pthread_join:

#include <pthread.h>
int pthread_join(pthread_t thread,void **retval);

对于一个默认线程的线程A来说,线程占用的资源并不会因为执行结束而得到释放

  • 成功返回0,失败返回错误码
  • thread要回收的线程对象
  • 调用线程阻塞直到thread结束 
  • *retval接受线程thread的返回值

示例代码:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>void *func(void *arg)
{printf("This is child thread\n");sleep(1);pthread_exit("thread return");
}
int main()
{void *retv;pthread_t tid;pthread_create(&tid,NULL,func,NULL);pthread_join(tid,&retv);//线程没退出,此处一直阻塞状态printf("thread ret = %s\n",(char *)retv);sleep(1);
}

 运行结果:

注意:

       pthread_join是阻塞函数,如果回收的线程没有结束,则一直等待

线程分离pthread_detach:

int pthread_detach(pthread_t thread);

 成功:0,失败:错误号

  • 指定该状态,线程主动与主控线程断开关系。线程结束后(不会产生僵尸线程)

示例代码: 

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>void *func(void *arg)
{pthread_detach(pthread_self());printf("This is child thread\n");sleep(1);pthread_exit("thread return");
}
int main()
{void *retv;pthread_t tid[5];int i;for (i = 0; i < 5; i++){pthread_create(&tid[i],NULL,func,NULL);//pthread_detach(tid);}while (1){sleep(1);}}

 运行结果:

 通过线程属性来设置分离态:

示例代码:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>void *func(void *arg)
{//pthread_detach(pthread_self());printf("This is child thread\n");sleep(1);pthread_exit("thread return");
}
int main()
{void *retv;pthread_t tid[5];int i;pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);for (i = 0; i < 5; i++){pthread_create(&tid[i],NULL,func,NULL);//pthread_detach(tid);}while (1){sleep(1);}}

四、线程回收内存演示

示例代码:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>void *func(void *arg)
{printf("This is child thread\n");sleep(25);pthread_exit("thread return");
}
int main()
{void *retv;pthread_t tid[100];int i;for (i = 0; i < 100; i++){pthread_create(&tid[i],NULL,func,NULL);}for (i = 0; i < 100; i++){pthread_join(tid[i],&retv);printf("thread ret=%s\n",(char *)retv);}while (1){sleep(1);}
}

代码运行期间:

查看进程Pid

使用top命令动态查看内存大小,可以看出内存会变小。

 使用pthread_detach代码一样效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/636841.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【论文解读】LERF:语言嵌入的辐射场(ICCV 2023 Oral)

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 论文链接&#xff1a;https://arxiv.org/abs/2303.09553 项目主页&#xff1a;https://lerf.io](https://lerf.io 图 1&#xff1a;语言嵌入辐射场 (LERF)。 LERF 将 CLIP 表示建立在密集、多尺度的 3D 场中。…

Oracle SQL Developer执行sql脚本文件

文件过于大&#xff0c;无法打开&#xff0c;直接在界面执行。 ①将文件放置到D盘&#xff0c;文件名 daochu5.sql ② 在工具执行SQL界面输入 d:\daochu5.sql;,点击运行按钮运行

Shell 脚本实现自动启动程序、日志管理和定时任务监控

简介 本篇将通过Shell 脚本实现自动启动Java程序、日志管理和定时任务监控。脚本启动程序具灵活定制、可移植性和扩展性强的优点&#xff0c;可以根据需要添加额外的功能、配置选项和自定义行为&#xff0c;从而满足更具体的要求。 脚本编写 vim start_program.sh#!/bin/bas…

Swift抓取某网站律师内容并做排名筛选

有个很要好的朋友&#xff0c;今天找我说他的朋友欠他钱&#xff0c;因为工程上面的事情&#xff0c;所以一直没拿到款。想让我找个靠谱的律师帮他打官司&#xff0c;因为这个也不是我的强项&#xff0c;也没有这方面的经验。随即从律师网站爬取对应律师口碑以及成功案例&#…

【第七在线】利用大数据与AI,智能商品计划的未来已来

随着科技的快速发展&#xff0c;大数据和人工智能(AI)已经成为各行各业变革的重要驱动力。在服装行业&#xff0c;这两大技术的结合正在深刻改变着传统的商品计划方式&#xff0c;引领着智能商品计划的未来。 一、大数据与AI在智能商品计划中的角色 大数据为智能商品计划提供了…

【设计模式】腾讯二面:自动贩卖机/音频播放器使用了什么设计模式?

状态模式是什么&#xff1f; 状态模式&#xff0c;也被称作状态对象模式&#xff0c;是一种行为设计模式。 当一个对象的内在状态改变时&#xff0c;允许改变其行为&#xff0c;这个对象看起来像是改变了其类。 它让对象在其内部状态改变时改变自己的行为。外部调用者无需了…

数据结构学习之双向链表(各种操作合集)

双向链表&#xff08;各种操作合集&#xff09; 双向链表的两种创建方式&#xff1a; 方法1&#xff1a;根据函数的返回值创建 通过返回值返回所申请的头结点所在的内存空间首地址&#xff0c;即创建双向链表的头结点&#xff0c;代码如下&#xff1a; 示例代码&#xff1a;…

【设计模式】什么是外观模式并给出例子!

什么是外观模式&#xff1f; 外观模式是一种结构型设计模式&#xff0c;主要用于为复杂系统、库或框架提供一种简化的接口。这种模式通过定义一个包含单个方法的高级接口&#xff0c;来隐藏系统的复杂性&#xff0c;使得对外的API变得简洁并易于使用。 为什么要使用外观模式&a…

Ubuntu安装mysql8详细步骤

1、拉取镜像 docker pull mysql:8.0.20 2、启动镜像 docker run -p 3307:3306 --name mysql8 -e MYSQL_ROOT_PASSWORD123456 -d mysql:8.0.20 检查是否启动成功 docker ps 3、配置挂载 创建挂载目录&#xff08;请检查保证创建成功&#xff09; mkdir -p /docker/mysql8.0.20/…

统计学-R语言-7.2

文章目录 前言总体均值的检验总体均值的检验(一个总体均值的检验)两个总体均值之差的检验 总体比例的检验一个总体比例的检验 练习 前言 本篇将继续上篇文章进行介绍。 总体均值的检验 总体均值的检验(一个总体均值的检验) 小样本的检验 假定条件 小样本(n<30) 总体服从正…

如何利用 APM 追踪完整的类函数调用

通常&#xff0c;应用接入 APM 后&#xff0c;可以追踪到应用相关组件、服务间的调用链路情况&#xff0c;如 Tomcat、Redis、MySQL 等&#xff0c;这是因为 APM 对于标准性组件做了插桩处理&#xff0c;从而更好的观测到在实际使用过程中组件调用对应用的影响。 而在实际生产…

揭秘AI换脸技术:从原理到应用

随着人工智能技术的不断发展&#xff0c;AI换脸技术逐渐成为人们关注的焦点。这项神奇的技术能够将一张图像或视频中的人脸替换成另一张人脸&#xff0c;让人不禁惊叹科技的神奇。那么&#xff0c;AI换脸技术究竟是如何实现的呢&#xff1f;本文将带您深入了解AI换脸技术的原理…

55 C++ 多线程 返回值问题。引出的 async,future,packaged_task,promise.

一 前提&#xff0c;thread返回值的写法 在之前的代码中&#xff0c;我们并没有讨论 子线程的返回值问题。 这一章就考虑这个问题怎么处理。 下面我们先按照之前的写法&#xff0c;我们需要返回值时的可能的fix方案。 //如果线程有返回值&#xff0c;并且主线程要得到这个返…

《WebKit 技术内幕》之五(3): HTML解释器和DOM 模型

3 DOM的事件机制 基于 WebKit 的浏览器事件处理过程&#xff1a;首先检测事件发生处的元素有无监听者&#xff0c;如果网页的相关节点注册了事件的监听者则浏览器会将事件派发给 WebKit 内核来处理。另外浏览器可能也需要处理这样的事件&#xff08;浏览器对于有些事件必须响应…

logstack 日志技术栈-04-opensource 开源工具 OpenObserve+Grafana Loki

日志技术栈 日志管理包含日志数据存储、处理、分析和可视化&#xff0c;通过利用日志管理工具&#xff0c;可以监控性能趋势、解决问题、检测异常并优化整体系统性能。 近年来&#xff0c;开源日志管理解决方案在大家寻求灵活且经济有效的方式来管理现代系统典型的大量日志数…

JVM问题分析处理手册

一.前言 各位开发和运维同学&#xff0c;在项目实施落地的过程中&#xff0c;尤其是使用EDAS、DRDS、MQ这些java中间件时&#xff0c;肯定会遇到不少JAVA程序运行和JVM的问题。我结合过去遇到的各种各样的问题和实际处理经验&#xff0c;总结了JAVA问题的处理方式&#xff0c;…

soso移动营业大厅(纯后端+MySQL数据库+JDBC)

一、项目需求 中国移动,中国联通,中国电信是国内3大通信运营商,每个运营商都提供了不同的品牌套餐来应对不同的用户群,比如北京移动主要有全球通,神州行,动感地带等3大品牌套餐,每种套餐的内容和费用不同,嗖嗖移动是一个假定的通信运营商,提供了话痨套餐,网虫套餐,超人套餐,各…

等离子环制作

免责声明 在您参考该博客制作等离子环前&#xff0c;请仔细阅读以下重要安全警告和免责说明。使用本文档即表示您已充分了解并同意以下条款&#xff1a; 等离子环的危险性&#xff1a;等离子环在运行时玻璃瓶身会产生高温&#xff0c;存在低温烧伤风险。任何时候都不建议用手…

C for Graphic:Sliced Circle Image

不做UI不知道&#xff0c;没想到时至今日&#xff0c;ugui居然没有sliced filled image模式&#xff0c;用circle做filled&#xff0c;不能用sliced九宫格图&#xff0c;导致每次使用这个效果必须一张新图&#xff0c;何其浪费资源。 原始功能如下&#xff1a; 我…

contextlib.contextmanager函数装饰器介绍

contextlib 是 Python 标准库中的一个模块&#xff0c;提供了一些用于创建上下文管理器&#xff08;context manager&#xff09;的实用工具。contextlib.contextmanager 是 contextlib 模块中的一个装饰器&#xff0c;用于将一个生成器函数转换为上下文管理器。通过使用这个装…