当前位置: 首页 > news >正文

Linux探秘坊-------15.线程概念与控制

1.线程概念

1.什么是线程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.线程 vs 进程

在这里插入图片描述
不同的操作系统有不同的实现方式:

  • linux :直接使用pcb的功能来模拟线程,不创建新的数据结构
  • windows: 使用新的数据结构TCB,来进行实现,一个PCB里有很多个TCB

3.资源划分

详情可见操作系统书籍中的存储器管理虚拟存储器管理章节!!!!

4.线程理解

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.线程和进程的区别

在这里插入图片描述

  • 黄字代表线程特有的私有数据
  • 一组寄存器和上下文数据---------------证明线程是可以被独立调用
  • 栈--------------证明线程是动态的

1.进程的线程共享!!!!!!!!!!

同⼀地址空间,因此 Text Segment 、 Data Segment 都是共享的,如果定义⼀个函数,在各线程中都可以调⽤ ,如果定义⼀个全局变量,在各线程中都可以访问到, 除此之外,各线程还共享以下进程资源和环境:

  • ⽂件描述符表 (fd)
  • 每种信号的处理⽅式(SIG_IGN、SIG_DFL或者⾃定义的信号处理函数)
  • 当前⼯作⽬录
  • ⽤⼾id和组id

1.父子进程只有代码段是共享的,但主线程和子线程连地址空间都是共享的,所以他们可以使用共享的函数和全局变量 意思就是如果子线程的全局变量被修改了,主线程看到的是同一个全局变量,也会变化 轻松实现类似进程间通信!!!!!!!
2.而全局变量在父子进程中是写实拷贝,子变父不变 !!!!!!!!!

在这里插入图片描述

3.linux的线程控制

1.线程创建

创建函数:
在这里插入图片描述
运行后使用 ps - aL指令查看线程
在这里插入图片描述

2.pthread库的引入----为什么需要有线程库?

在这里插入图片描述

4.pthread库的使用

  • 与线程有关的函数构成了⼀个完整的系列,绝⼤多数函数的名字都是“pthread_”打头的
    • 要使⽤这些函数库,要通过引⼊头⽂件 <pthread.h>
    链接这些线程函数库时要使⽤编译器命令的“-lpthread”选项

1.线程创建—pthread_create()

在这里插入图片描述

  • thread是新线程的标识符,是输出型参数(让主线程获取,便于调用其他函数)

2.线程等待—pthread_join()

在这里插入图片描述

  • 这里retval拿到的是子线程的退出码,即子线程函数的返回值,但返回值是void *
  • 所以retval的类型应当是void* 的地址类型即void**

在这里插入图片描述

  • 其中,routine是子线程的入口函数,routine函数结束的话子线程也就结束了

3.线程取消或终止—pthread_exit()/pthread_cancel()

1-----------------pthread_exit()
在这里插入图片描述
2-----------------pthread_cancel()

在这里插入图片描述

  • 如果线程被主线程或其他线程取消,那么主线程join函数得到的返回值固定为-1

4.线程分离—int pthread_detach(pthread_t thread);

在这里插入图片描述

5.线程ID及进程地址空间布局

1.--------------------------pthread_self函数获取id
在这里插入图片描述
2.--------------------------pthread库的动态链接
在这里插入图片描述

  • 所有的线程都是在thread库中建立的,线程的管理块都存储在库中具体的pcb由用户使用系统调用在内核中建立

在这里插入图片描述

  • 创建线程的具体图例

在这里插入图片描述

6.线程互斥

来看一个买票的例子:

/ 操作共享变量会有问题的售票系统代码
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int ticket = 100;
void* route(void* arg) {char* id = (char*)arg;while (1) {if (ticket > 0) {usleep(1000);printf("%s sells ticket:%d\n", id, ticket);ticket--;} else {break;}}
}
int main(void) {pthread_t t1, t2, t3, t4;pthread_create(&t1, NULL, route, (void*)"thread 1");pthread_create(&t2, NULL, route, (void*)"thread 2");pthread_create(&t3, NULL, route, (void*)"thread 3");pthread_create(&t4, NULL, route, (void*)"thread 4");pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);
}

在这里插入图片描述

  • 为了避免买票变成负数,所以要使用 来保证线程间的互斥

为什么会变成负数??????

  • 因为ticket–操作并不是原子的----------即无法一步完成------要先把ticket大小传入cpu,再在cpu中进行运算,最后再写回ticket全局变量中--------一共有三步
  • 可能某一个线程计算完后ticket为0,但还没写回ticket,另一个线程就又开始运行,这个时候ticket是1,还能通过if条件语句,最后两个线程都执行ticket–,全部写回后,ticket变成了-1!!!!1

在这里插入图片描述

1.锁的使用

#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int ticket = 100;
pthread_mutex_t mutex;//设置锁----这里是全局锁,用完后会自动销毁
void* route(void* arg) 
{char* id = (char*)arg;while (1) {pthread_mutex_lock(&mutex);//pthread_mutex_lock--------上锁if (ticket > 0) {usleep(1000);printf("%s sells ticket:%d\n", id, ticket);ticket--;pthread_mutex_unlock(&mutex);// pthread_mutex_unlock--------解锁} else {pthread_mutex_unlock(&mutex);// pthread_mutex_unlock--------解锁break;}}return nullptr;
}
int main(void) {pthread_t t1, t2, t3, t4;pthread_mutex_init(&mutex, NULL);// pthread_mutex_init------初始化锁pthread_create(&t1, NULL, route, (void*)"thread 1");pthread_create(&t2, NULL, route, (void*)"thread 2");pthread_create(&t3, NULL, route, (void*)"thread 3");pthread_create(&t4, NULL, route, (void*)"thread 4");pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);pthread_mutex_destroy(&mutex);//pthread_mutex_destroy-------删除锁
}

7.线程同步

在这里插入图片描述

1.条件变量

-------------------为了避免加锁后导致线程饥饿而设置的变量

http://www.dtcms.com/a/285233.html

相关文章:

  • 内容安全策略(CSP)详解:Web安全的关键防线
  • SegNet:一种用于图像分割的深度卷积编码器解码器架构
  • 简单易懂,动态分区分配算法
  • Leetcode刷题营第二十九,三十题:二叉树的中序以及后序遍历
  • mongosh 安装记录
  • ruoyi-cloud启动常见问题处理
  • set、map 比数组,json 对象的性能更好原因分析
  • Python元组(Tuple)指南
  • [RAG system] 信息检索器 | BM25 Vector | Pickle格式 | HybridRetriever重排序
  • 教资科三【信息技术】— 学科知识: 第二章(计算机系统基础)
  • 【程序地址空间】虚拟地址与页表转化
  • 自己训练大模型?MiniMind 全流程解析 (二) 监督微调SFT
  • 【Bluedroid】A2dp Sink初始化(init_sink)源码分析[2]:btif_a2dp_sink_init
  • JAVA几个注解记录
  • 【Spring AI Alibaba实战Demo】通过Spring AI Alibaba接入本地部署的大模型和线上大模型,实现流式简单对话
  • Ubuntu FTP服务搭建与配置
  • Product Hunt 每日热榜 | 2025-07-17
  • druid连接池
  • Xss-labs 靶场lever1~lever8通关练习
  • 第12章 存储类、链接和内存管理
  • window下 wsl 下怎么配置 kimi-k2 驱动 Claude Code
  • 网络通信原理
  • 订货系统能接金蝶吗是什么?
  • FreeRTOS—中断管理
  • 一文学会c++vector
  • Web前端:JavaScript鼠标事件
  • 实习十二——协议分层
  • pytorch小记(三十一):深入解析 PyTorch 权重初始化:`xavier_normal_` 与 `constant_`
  • 基于selenium的pyse自动化测试框架
  • MyUI1.0全新现代化 Vue.js 组件库框架上线