linux——线程(1)

文章目录

  • 1.线程概念
    • 1.1 什么是线程
    • 1.2 线程和进程区别
    • 1.3 线程实现原理
    • 1.4 三级映射
    • 1.5 线程共享资源
    • 1.6 线程非共享资源
    • 1.7 线程优、缺点
  • 2.线程控制原语
    • 2.1 pthread_self 函数
    • 2.2 pthread_create 函数
  • 3.线程与共享
    • 3.1 线程共享全局变量
  • 4.线程退出
    • 4.1 pthread_exit 函数

1.线程概念

1.1 什么是线程

线程:LWP(light weight process), 轻量级的进程,本质仍是进程(在 Linux 环境下)。
线程是进程的子任务,实现进程内部的并发,线程也是CPU调度和执行的最小单位。

1.2 线程和进程区别

进程拥有独立的4G内存地址空间,拥有PCB;线程有独立的 PCB,但没有独立的地址空间(共享)。
进程是最小分配资源单位;线程是最小的执行单位。
进程通信方式:管道、系统IPC(消息队列、信号量、信号、共享内存)、套接字;线程通信方式:临界区、互斥量、信号量、事件(信号)。

1.3 线程实现原理

  1. 轻量级进程(light-weight process),也有 PCB,创建线程函数(pthead_create)和创建进程(fork)的底层函数一样,都是 clone函数
  2. 从内核里看进程和线程是一样的,都有各自不同的 PCB,但是 PCB 中指向内存资源的三级页表是相同的
  3. 线程可看做寄存器和栈的集合
  4. 对于进程来说,相同的地址(同一个虚拟地址)在不同的进程中,反复使用而不冲突。原因是他们虽虚拟址一样,但页目录、页表、物理页面各不相同。相同的虚拟址,映射到不同的物理页面内存单元,最终访问不同的物理页面。
    但线程不同,两个线程具有各自独立的 PCB,但共享同一个页目录,也就共享同一个页表和物理页面。所以两个 PCB 共享一个地址空间。实际上,无论是创建进程的 fork,还是创建线程的 pthread_create,底层实现都是调用同一个内核函数 clone。
    如果复制对方的地址空间,那么就产出一个“进程”;如果共享对方的地址空间,就产生一个“线程”。
察看 LWP /线程号:ps –Lf pid 查看指定进程的 lwp 号(线程号,而非线程ID)
zhaoxr@zhaoxr-ThinkPad-E450:~$ ps -Lf 32639
UID          PID    PPID     LWP  C NLWP STIME TTY      STAT   TIME CMD
zhaoxr     32639    1815   32639  0   23 20:17 ?        SLl    0:01 /opt/google/chrome/chrome
zhaoxr     32639    1815   32648  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32656  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32657  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32661  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32662  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32663  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32664  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32665  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32666  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32667  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32668  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32671  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32672  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32673  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32674  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32675  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32676  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32678  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32680  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32695  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32716  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome
zhaoxr     32639    1815   32774  0   23 20:17 ?        SLl    0:00 /opt/google/chrome/chrome

1.4 三级映射

在这里插入图片描述

1.5 线程共享资源

1.文件描述符表,在同一个进程内,a线程和b线程共享文件描述符
2.每种信号的处理方式,线程和信号组合复杂,最好不要把它们搅合在一起
3.当前工作目录
4.用户 ID 和组 ID
5.内存地址空间 (.text/.data/.bss/heap/共享库),除了栈空间

1.6 线程非共享资源

1.线程 id
2.处理器现场和栈指针(内核栈)
3.独立的栈空间(用户空间栈)
4.errno 变量,很特殊的变量,是全局变量,在数据.data段,但是共享
5.信号屏蔽字
6.调度优先级

1.7 线程优、缺点

优点: 1. 提高程序并发性 2. 开销小 3. 数据通信、共享数据方便
缺点: 1. 库函数,不稳定 2. 调试、编写困难、gdb 不支持 3. 对信号支持不好
优点相对突出,缺点均不是硬伤。Linux 下由于实现方法导致进程、线程差别不是很大。

2.线程控制原语

线程所有操作函数 pthread_* 是库函数,而非系统调用,
对线程相关函数gcc编译时,需要链接第三方库-pthread

2.1 pthread_self 函数

获取线程 ID。其作用对应进程中 getpid() 函数。
pthread_t pthread_self(void);返回值:成功:0; 失败:无!线程 ID:pthread_t 类型,本质:在 Linux 下为无符号整数(%lu),其他系统中可能是结构体实现
线程 ID 是进程内部,识别标志。(两个进程间,线程 ID 允许相同)注意:不应使用全局变量 pthread_t tid,在子线程中通过 pthread_create 传出参数来获取线程 ID,
而应使用pthread_self。

2.2 pthread_create 函数

创建一个新线程。 其作用,对应进程中 fork() 函数。
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
返回值:成功:0; 失败:错误号 -----Linux 环境下,所有线程特点,失败均直接返回错误号。
参数:
pthread_t:当前 Linux 中可理解为:typedef unsigned long int pthread_t;
参数 1:传出参数,保存系统为我们分配好的线程 ID
参数 2:通常传 NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。
参数 3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。
参数 4:线程主函数执行期间所使用的参数。
在一个线程中调用 pthread_create()创建新的线程后,当前线程从 pthread_create()返回继续往下执行,
而新的线程所执行的代码由我们传给 pthread_create 的函数指针 start_routine 决定。
start_routine 函数接收一个参数,是通过pthread_create 的 arg 参数传递给它的,
该参数的类型为 void *,这个指针按什么类型解释由调用者自己定义。start_routine 的返回值类型也是 void *,这个指针的含义同样由调用者自己定义。start_routine 返回时,这个线程就退出了,
其它线程可以调用 pthread_join 得到 start_routine 的返回值,
类似于父进程调用 wait(2)得到子进程的退出状态,稍后详细介绍 pthread_join。
pthread_create 成功返回后,新创建的线程的 id 被填写到 thread 参数所指向的内存单元。
我们知道进程 id 的类型是 pid_t,每个进程的 id 在整个系统中是唯一的,
调用 getpid(2)可以获得当前进程的 id,是一个正整数值。线程id 的类型是 thread_t,它只在当前进程中保证是唯一的,在不同的系统中 thread_t 这个类型有不同的实现,
它可能是一个整数值,也可能是一个结构体,也可能是一个地址,
所以不能简单地当成整数用 printf 打印,调用 pthread_self(3)可以获得当前线程的 id。attr 参数表示线程属性,本节不深入讨论线程属性,所有代码例子都传 NULL 给 attr 参数,
表示线程属性取缺省值,感兴趣的读者可以参考 APUE。
#include<stdio.h>
#include<pthread.h>
#include <stdlib.h>
#include<unistd.h>void* print(void* arg){printf("in print:pthread id=%lu,pid=%u\n",pthread_self(),getpid());return NULL;
}
int main()
{pthread_t tid;//线程IDprintf("in main1:pthread id=%lu,pid=%u\n",pthread_self(),getpid());tid=pthread_create(&tid,NULL,print,NULL);sleep(1);if(tid!=0){printf("pthread_create error\n");exit(1);}printf("in main1:pthread id=%lu,pid=%u\n",pthread_self(),getpid());return 0;
}
zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ vim pthread_create.c                            
zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ gcc pthread_create.c -o pthread_create -lpthread
zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ ./pthread_create                                
in main1:pthread id=140607852943168,pid=33317
in print:pthread id=140607852939008,pid=33317
in main1:pthread id=140607852943168,pid=33317
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>void* func(void* arg){int i=(int)arg;//sleep(i);printf("第%d个线程,pthread id=%lu,pid=%u\n",i,pthread_self(),getpid());return NULL;
}
int main()
{pthread_t tid;int i,ret;for(int i=0;i<5;i++){ret=pthread_create(&tid,NULL,func,(void*)i);if(ret!=0){fprintf(stderr,"pthread_create error:%s\n",strerror(ret));exit(1);}}sleep(1);printf("main pthread id=%lu,pid=%u\n",pthread_self(),getpid());return 0;
}
zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ ./cycle_pthread_create     
第0个线程,pthread id=139641383798528,pid=365263个线程,pthread id=139641265059584,pid=365264个线程,pthread id=139641358620416,pid=365261个线程,pthread id=139641375405824,pid=365262个线程,pthread id=139641367013120,pid=36526
main pthread id=139641383802688,pid=36526

3.线程与共享

3.1 线程共享全局变量

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>int a=10;void* func1(void* arg){a=100;printf("pthread id=%lu,a=%d\n",pthread_self(),a);return NULL;
}void* func2(void* arg){printf("pthread id=%lu,a=%d\n",pthread_self(),a);return NULL;
}
int main()
{pthread_t tid1,tid2;int ret;ret=pthread_create(&tid1,NULL,func1,NULL);if(ret!=0){printf("pthread create error\n");exit(1);}sleep(1);ret=pthread_create(&tid2,NULL,func2,NULL);if(ret!=0){printf("pthread create error\n");exit(1);}sleep(1);return 0;
}
zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ ./pthread_value     
pthread id=140622421137152,a=100
pthread id=140622412744448,a=100

线程间共享全局变量!
【牢记】:线程默认共享数据段、代码段等地址空间,常用的是全局变量。而进程不共享全局变量,只能借助 mmap。

4.线程退出

4.1 pthread_exit 函数

将单个线程退出

void pthread_exit(void *retval); 参数:retval 表示线程退出状态,通常传 NULL
思考:使用 exit 将指定线程退出,可以吗? 【pthrd_exit.c】
结论:线程中,禁止使用 exit 函数,会导致进程内所有线程全部退出。

在不添加 sleep 控制输出顺序的情况下。pthread_create 在循环中,几乎瞬间创建 5 个线程,但只有第 1 个线程有机会输出(或者第 2 个也有,也可能没有,取决于内核调度)如果第 3 个线程执行了 exit,将整个进程退出了,所以全部线程退出了。
所以,多线程环境中,应尽量少用,或者不使用 exit 函数,取而代之使用 pthread_exit 函数,将单个线程退出。
任何线程里 exit 导致进程退出,其他线程未工作结束,主控线程退出时不能 return 或 exit。

另注意,pthread_exit 或者 return 返回的指针所指向的内存单元必须是全局的或者是用 malloc 分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。

#include<stdio.h>
#include<pthread.h>
#include <stdlib.h>
#include<unistd.h>void* print(void* arg){sleep(1);printf("in print:pthread id=%lu,pid=%u\n",pthread_self(),getpid());return NULL;
}
int main()
{pthread_t tid;//线程IDint ret;printf("in main1:pthread id=%lu,pid=%u\n",pthread_self(),getpid());ret=pthread_create(&tid,NULL,print,NULL);sleep(1);if(ret!=0){printf("pthread_create error\n");exit(1);}printf("in main1:pthread id=%lu,pid=%u\n",pthread_self(),getpid());pthread_exit(NULL);
}
zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ ./pthread_exit       
in main1:pthread id=139696593151808,pid=36805
in main1:pthread id=139696593151808,pid=36805
in print:pthread id=139696593147648,pid=36805

main主函数中没有使用return,并且不能使用exit函数,且其等待其它线程结束进程才结束。

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

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

相关文章

Redis压缩列表原理与应用分析

摘要 Redis是一款著名的key-value内存数据库软件&#xff0c;同时也是一款卓越的数据结构服务软件。它支持字符串、列表、哈希表、集合、有序集合五种数据结构类型&#xff0c;同时每种数据结构类型针对不同的应用场景又支持不同的编码方式。这篇文章主要介绍压缩列表编码&…

Science公布2021年度十大科学突破,AI这项前所未有的突破上榜

来源&#xff1a; 学术头条撰文&#xff1a;朱哼哼编审&#xff1a;王哈哈排版&#xff1a;李雪薇2021 年 11 月 17 日&#xff0c;Science 杂志公布了 2021 年的年度科学突破榜单&#xff0c;AlphaFold 和 RoseTTA-fold 两种基于人工智能预测蛋白质结构的技术位列榜首。除此之…

OpenAI教GPT-3学会上网,「全知全能」的AI模型上线了

来源&#xff1a;机器学习研究组订阅它被命名为 WebGPT&#xff0c;OpenAI 认为浏览网页的方式提高了 AI 解答问题的准确性。如果 AI 学会上网&#xff0c;那么它就拥有了无限获取知识的方式&#xff0c;之后会发生什么就不太好预测了。于是著名 AI 研究机构 OpenAI 教那个开启…

Hadoop(2):常见的MapReduce[在Ubuntu中运行!]

1 以词频统计为例子介绍 mapreduce怎么写出来的 弄清楚MapReduce的各个过程&#xff1a; 将文件输入后&#xff0c;返回的<k1,v1>代表的含义是&#xff1a;k1表示偏移量&#xff0c;即v1的第一个字母在文件中的索引&#xff08;从0开始数的&#xff09;&#xff1b;v1表…

springboot学习笔记-01-springboot-helloworld的编写以及原理初步了解(自动装配)

文章目录原理初探主程序关于spring boot&#xff0c;谈谈你的理解&#xff1a;微服务阶段原理初探 pom.xml spring-boot-dependencies&#xff1a;核心依赖在父工程中&#xff01;我们在写或者引入一些springboot依赖的时候&#xff0c;不需要指定版本&#xff0c;就因为有这…

2022年:机器人技术的重大革命

来源&#xff1a;ScienceAI编辑&#xff1a;萝卜皮一段时间以来&#xff0c;跟踪机器人技术发展的人已经注意到该领域的一场无声革命。虽然自动驾驶汽车占据了所有的头条新闻&#xff0c;但人工智能、机器视觉和机器学习的交叉领域正在迅速成为下一阶段机器人技术的基础。通过将…

陈天奇高赞文章:新一代深度学习编译技术变革和展望

来源&#xff1a;机器之心作者&#xff1a;陈天奇陈天奇是机器学习领域著名的青年华人学者之一&#xff0c;本科毕业于上海交通大学ACM班&#xff0c;博士毕业于华盛顿大学计算机系&#xff0c;研究方向为大规模机器学习。在本文中&#xff0c;陈天奇回答了目前深度学习编译技术…

操作系统欢乐笔记-01-带你推开操作系统的大门(雾)

B站-操作系统-哈尔并工业大学-劝退警告223 文章目录1.什么是操作系统&#xff1f;什么是操作系统&#xff1f;小目标&#xff1f;2.揭开钢琴的盖子熟悉的win开机画面从白纸到图灵机冯-诺依曼一拍脑袋瓜&#xff0c;他说摁下开机键这段不是rap 223 劝退警告emmmmm1.什么是操作系…

2022年值得关注的22项新兴技术

来源&#xff1a;参考消息网英国《经济学人》网站11月8日发表题为《下一个是什么&#xff1f;2022年值得关注的22项新兴技术》的文章。在文章列举的22项新技术中&#xff0c;既有今年大热的“元宇宙”、太空旅游、脑机接口&#xff0c;也有备受期待的量子计算、艾滋病病毒疫苗……

分别安装搭建lamp服务环境

一、 分别安装搭建lamp服务环境 准备工作&#xff1a; 1、配置防火墙&#xff0c;开启80端口、3306端口vi /etc/sysconfig/iptables-A INPUT -m state –state NEW -m tcp -p tcp –dport 80 -j ACCEPT #允许80端口通过防火墙-A INPUT -m state –state NEW -m tcp -p tcp –dp…

springdata学习笔记-01-helloworld-(暂时不全223)

第一天 orm思想和hibernate以及jpa的概述和jpd的基本操作 传统jdbc操作 获取链接创建statement对象可以对占位符赋值发送查询 操作繁琐占位符赋值麻烦 orm思想 主要目的&#xff1a;操作实体类就相当于操作数据库表建立两个映射关系 实体类和表的映射关系实体类中属性和表中…

nginx学习笔记-01nginx入门,环境搭建,常见命令

nginx学习笔记-01nginx入门&#xff0c;环境搭建&#xff0c;常见命令 文章目录nginx学习笔记-01nginx入门&#xff0c;环境搭建&#xff0c;常见命令1.nginx的基本概念2.nginx的安装&#xff0c;常用命令和配置文件3.nginx配置实例1.nginx的基本概念 nginx是什么&#xff0c;做…

MIT博士用概率编程让AI和人类一样看三维|NeurIPS 2021

来源&#xff1a;机器学习研究组订阅人与AI之间最大的区别就是对常识的利用&#xff01;无论各种AI模型在各大排行榜以何种性能超越了人类&#xff0c;它们在常识的利用上仍然远远不及人类&#xff0c;而这也正是目前AI研究中需要面临的一个巨大的挑战。对于自然语言处理的研究…

Unity Shader 2D水流效果

水流的模拟主要运用了顶点变换和纹理动画的结合&#xff1b; 顶点变换中&#xff0c;利用正弦函数模拟河流的大致形态&#xff0c;例如波长&#xff0c;振幅等。 纹理动画中&#xff0c;将纹理坐标朝某一方向持续滚动以形成流动的效果。 脚本如下&#xff1a; 1 Shader "M…

2022年智能家居十大预测新鲜出炉:全屋智能驶入快车道?健身镜成新宠……

来源&#xff1a;物联网智库 2021年接近尾声&#xff0c;这一年&#xff0c;新冠病毒仍旧没有离开地球&#xff0c;而在疫情常态化、工作与生活回归正轨之余&#xff0c;人们对于网络与虚拟世界的依赖度也陡然骤增。这一转变无疑将极大拉动消费端的数字化产业发展&#xff0c;除…

数据结构与算法——动态规划

文章目录1.内容概述2.爬楼梯2.1 题目描述2.算法思想2.3 代码实现3.打家劫舍3.1 题目描述3.2 算法思路3.3 代码实现4.最大子序和4.1 题目描述4.2 算法思路4.3 代码思路5. 零钱兑换5.1 题目描述5.2 算法思路5.3 代码实现6.三角形最小路径和6.1 题目描述6.2 算法思路6.3 代码实现7…

vue学习笔记-01-前端的发展历史(从后端到前端,再到前后端分离,再到全栈)

vue学习笔记-01-前端的发展历史&#xff08;从后端到前端&#xff0c;再到前后端分离&#xff0c;再到全栈&#xff09; 这篇文章是博主在看vue-前端发展简史的时候做的笔记&#xff0c;以供后续学习复习 文章目录vue学习笔记-01-前端的发展历史&#xff08;从后端到前端&#…

黑客帝国「缸中之脑」有眉目了?培养皿中百万人脑细胞学会打乒乓球,仅用了5分钟...

来源&#xff1a;机器之心编辑&#xff1a;张倩、杜伟既然生物神经元如此高效&#xff0c;为什么不拿来用呢&#xff1f;最新版本的《黑客帝国》还有两天才会上映&#xff0c;但最近的一些科技进展总让我们觉得&#xff0c;导演描述的世界似乎离我们越来越近了。其中一个进展来…

《Science》基因组比对的革命性技术

来源&#xff1a;生物通加州大学圣克鲁斯基因组研究所(UC Santa Cruz Genomics Institute)的研究人员推出了一种名为“长颈鹿”(Giraffe)的新工具&#xff0c;可以有效地将新的基因组序列绘制到代表多种不同人类基因组序列的“泛基因组”(pangenome)上。使用泛基因组学方法而不…

vue学习笔记-02-前端的发展历史浅谈mmvm设计理念

vue学习笔记-02-前端的发展历史浅谈mmvm设计理念 文章目录1. MVVM模式的实现者2.第一个vue程序3.什么是mvvm&#xff1f;4.为什么要用mvvm&#xff1f;5.mvvm的组成部分7.MVVM 模式的实现者8.为什么要使用 Vue.js1. MVVM模式的实现者 Model:模型层&#xff0c;在这里表示JavaSc…