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.锁的使用

#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-------删除锁
}

pthread 库是 POSIX 线程库,提供了多线程编程的 API,其中包括用于线程同步的锁机制。以下是 pthread 中常见的锁函数及其解释:


1. 互斥锁(Mutex)

互斥锁用于保护临界区,确保同一时间只有一个线程可以访问共享资源。

相关函数:
  • pthread_mutex_init
    初始化互斥锁。

    int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
    
    • mutex:指向互斥锁对象的指针。
    • attr:属性对象(通常设为 NULL 使用默认属性)。
    • 成功返回 0,失败返回错误码。
  • pthread_mutex_lock
    加锁。如果锁已被其他线程持有,则调用线程阻塞直到锁被释放。

    int pthread_mutex_lock(pthread_mutex_t *mutex);
    
  • pthread_mutex_trylock
    尝试加锁,如果锁已被持有则立即返回错误(非阻塞)。

    int pthread_mutex_trylock(pthread_mutex_t *mutex);
    
    • 成功返回 0,锁被持有时返回 EBUSY
  • pthread_mutex_unlock
    解锁。

    int pthread_mutex_unlock(pthread_mutex_t *mutex);
    
  • pthread_mutex_destroy
    销毁互斥锁,释放资源。

    int pthread_mutex_destroy(pthread_mutex_t *mutex);
    

7.线程同步

在这里插入图片描述

1.条件变量函数介绍

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

条件变量用于线程间通信,通常与互斥锁配合使用,实现线程的等待和唤醒机制。

相关函数:
  • pthread_cond_init //第二个变量基本是设置为nullptr
    初始化条件变量。

    int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
    
  • pthread_cond_wait // 第二个参数是上文的互斥锁
    等待条件变量,并释放关联的互斥锁(原子操作)。

    int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
    
  • pthread_cond_signal
    唤醒一个等待该条件变量的线程。

    int pthread_cond_signal(pthread_cond_t *cond);
    
  • pthread_cond_broadcast
    唤醒所有等待该条件变量的线程。

    int pthread_cond_broadcast(pthread_cond_t *cond);
    
  • pthread_cond_destroy
    销毁条件变量。

    int pthread_cond_destroy(pthread_cond_t *cond);
    
#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include <pthread.h>#define NUM 5
int cnt = 1000;pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER; // 定义锁
pthread_cond_t gcond = PTHREAD_COND_INITIALIZER;   // 定义条件变量// 等待是需要等,什么条件才会等呢?票数为0,等待之前,就要对资源的数量进行判定。
// 判定本身就是访问临界资源!,判断一定是在临界区内部的.
// 判定结果,也一定在临界资源内部。所以,条件不满足要休眠,一定是在临界区内休眠的!
// 证明一件事情:条件变量,可以允许线程等待
// 可以允许一个线程唤醒在cond等待的其他线程, 实现同步过程
void *threadrun(void *args)
{std::string name = static_cast<const char *>(args);while (true){pthread_mutex_lock(&glock);// 直接让对用的线程进行等待?? 临界资源不满足导致我们等待的!pthread_cond_wait(&gcond, &glock); // glock在pthread_cond_wait之前,会被自动释放掉std::cout << name << " 计算: " << cnt << std::endl;cnt++;pthread_mutex_unlock(&glock);}
}int main()
{std::vector<pthread_t> threads;for (int i = 0; i < NUM; i++){pthread_t tid;char *name = new char[64];snprintf(name, 64, "thread-%d", i);//snprintf函数往name中打印字符串int n = pthread_create(&tid, nullptr, threadrun, name);if (n != 0)continue;threads.push_back(tid);sleep(1);}sleep(3);// 每隔1s唤醒一个线程while(true){std::cout << "唤醒所有线程... " << std::endl;pthread_cond_broadcast(&gcond);// std::cout << "唤醒一个线程... " << std::endl;// pthread_cond_signal(&gcond);sleep(1);}for (auto &id : threads){int m = pthread_join(id, nullptr);(void)m;}return 0;
}

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

8.生产者消费者模型

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

  • 生产者和消费者之间要有顺序地进行工作,所以是同步的
基于阻塞队列实现生产者消费者模型:

----------------什么是阻塞队列?

在这里插入图片描述

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

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

相关文章

Github库镜像到本地私有Gitlab服务器

上一节我们看了如何架设自己的Gitlab服务器&#xff0c;今天我们看怎么把Github库转移到自己的Gitlab上。 首先登录github&#xff0c;进入自己的库复制地址。 克隆镜像库 在本地新建一个文件夹 在文件夹执行CMD指令 git clone --mirror gitgithub.com:thinbug/A.git–mirror参…

【C++】——类和对象(中)——默认成员函数

一、类的默认成员函数默认成员函数就是用户没有显示实现&#xff0c;不过编译器会自动生成的成员函数&#xff0c;称为默认成员函数。一个类默认成员函数一共有6个&#xff0c;在我们不写的情况下&#xff0c;编译器就会自动生成这6个成员函数&#xff0c;不过我们重点要学习的…

MATLAB知识点总结

1.将A图与B图相同范围内归一化显示在同一个figure上&#xff1a; figure, plot(A(150:450,500)/max(A(150:450,500))) hold on plot(D(150:450,500)/max(D(150:450,500)),‘R’) 将两幅图像的一定范围显示在同一图像上。 figure,plot(A(350,100:450)) hold on plot(G(350,100:4…

易天光通信10G SFP+ 1550nm 120KM 双纤光模块:远距离传输的实力担当

目录 前言 一、10G SFP双纤光模块概述 二、易天10G SFP 120KM 双纤光模块核心优势与应用 核心优势&#xff1a; 主要关键应用如下&#xff1a; 三、易天10G SFP 120KM 双纤光模块客户优势 总结 关于易天 前言 在构建高效稳定的网络架构时&#xff0c;10G SFP 光模块 12…

【深度学习】神经网络 批量标准化-part6

九、批量标准化是一种广泛使用的神经网络正则化技术&#xff0c;对每一层的输入进行标准化&#xff0c;进行缩放和平移&#xff0c;目的是加速训练&#xff0c;提高模型稳定性和泛化能力&#xff0c;通常在全连接层或是卷积层之和&#xff0c;激活函数之前使用核心思想对每一批…

【数据可视化-67】基于pyecharts的航空安全深度剖析:坠毁航班数据集可视化分析

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

【科研绘图系列】R语言绘制分组箱线图

文章目录 介绍 加载R包 数据下载 导入数据 画图1 画图2 合并图 系统信息 参考 介绍 【科研绘图系列】R语言绘制分组箱线图 加载R包 library(ggplot2) library(patchwork)rm(list = ls()) options(stringsAsFactors = F)

基于Android的旅游计划App

项目介绍系统打开进入登录页面&#xff0c;如果没有注册过账号&#xff0c;点击注册按钮输入账号、密码、邮箱即可注册&#xff0c;注册后可登录进入系统&#xff0c;系统分为首页、预订、我的三大模块&#xff0c;下面具体详细说说三大模块功能说明。1.首页显示旅游备忘或旅游…

【LeetCode 2163. 删除元素后和的最小差值】解析

目录LeetCode中国站原文原始题目题目描述示例 1&#xff1a;示例 2&#xff1a;提示&#xff1a;讲解分割线的艺术&#xff1a;前后缀分解与优先队列的完美邂逅第一部分&#xff1a;算法思想 —— “分割线”与前后缀分解1. 想象一条看不见的“分割线”2. 前后缀分解&#xff1…

控制鼠标和键盘

控制鼠标和键盘的Python库Python中有多个库可以用于控制鼠标和键盘&#xff0c;常用的包括pyautogui、pynput、keyboard和mouse等。这些库提供了模拟用户输入的功能&#xff0c;适用于自动化测试、GUI操作等场景。使用pyautogui控制鼠标pyautogui是一个跨平台的库&#xff0c;支…

基于按键开源MultiButton框架深入理解代码框架(二)(指针的深入理解与应用)

文章目录2、针对该开源框架理解3、分析代码3.1 再谈指针、数组、数组指针3.2 继续分析源码2、针对该开源框架理解 在编写按键模块的框架中&#xff0c;一定要先梳理按键相关的结构体、枚举等变量。这些数据是判断按键按下、状态跳转、以及绑定按键事件的核心。 这一部分定义是…

web前端渡一大师课 CSS属性计算过程

你是否了解CSS 的属性计算过程呢? <body> <h1>这是一个h1标题</h1> </body> 目前我们没有设置改h1的任何样式,但是却能看到改h1有一定的默认样式,例如有默认的字体大小,默认的颜色 那么问题来了,我们这个h1元素上面除了有默认字体大小,默认颜色等…

Redis高频面试题:利用I/O多路复用实现高并发

Redis 通过 I/O 多路复用&#xff08;I/O Multiplexing&#xff09;技术实现高并发&#xff0c;这是其单线程模型能够高效处理大量客户端连接的关键。以下是通俗易懂的解释&#xff0c;结合 Redis 的工作原理&#xff0c;详细说明其实现过程。 1. 什么是 I/O 多路复用&#xff…

爬虫小知识(二)网页进行交互

一、提交信息到网页 1、模块核心逻辑 “提交信息到网页” 是网络交互关键环节&#xff0c;借助 requests 库的 post() 函数&#xff0c;能模拟浏览器向网页发数据&#xff08;如表单、文件 &#xff09;&#xff0c;实现信息上传&#xff0c;让我们能与网页背后的服务器 “沟通…

WPF学习(五)

文章目录一、FileStream和StreamWriter理解1.1、具体关系解析1.2、类比理解1.3、总结1.4、示例代码1.5、 WriteLine()和 Write&#xff08;&#xff09;的区别1.6、 StreamWriter.Close的作用二、一、FileStream和StreamWriter理解 在 C# 中&#xff0c;StreamWriter 和 FileS…

ctf.show-web习题-web2-最简单的sql注入-flag获取详解、总结

解题思路打开靶场既然提示是最简单的sql注入了&#xff0c;那么直接尝试永真登录1 or 11#这里闭合就是简单的单引号可以看到没登录成功&#xff0c;但是有回显&#xff1a;欢迎你&#xff0c;ctfshowsql注入最喜欢的就是回显了&#xff01;这题的思路就是靠这个回显&#xff0c…

upload-labs 靶场通关(1-20)

目录 Pass-01(JS 绕过) Pass-02(文件类型验证) Pass-03(黑名单验证) Pass-04(黑名单验证.htaccess) Pass-05(大小写绕过) Pass-06(末尾空格) Pass-07(增加一个.) Pass-08(增加一个::$DATA) Pass-09&#xff08;代码不严谨&#xff09; Pass-10&#xff08;PPHPHP&am…

[附源码+数据库+毕业论文]基于Spring+MyBatis+MySQL+Maven+vue实现的酒店预订管理系统,推荐!

摘 要 使用旧方法对酒店预订信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在酒店预订信息的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问题。 这次开发的酒店预订管理系…

LSTM入门案例(时间序列预测)| pytorch实现(可复现)

需求 假如我有一个时间序列&#xff0c;例如是前113天的价格数据&#xff08;训练集&#xff09;&#xff0c;然后我希望借此预测后30天的数据&#xff08;测试集&#xff09;&#xff0c;实际上这143天的价格数据都已经有了。这里为了简单&#xff0c;每一天的数据只有一个价…

Axure RP 10 预览显示“无标题文档”的空白问题探索【护航版】

1. 安装情况 官网 Axure RP 10&#xff1a;Download Axure RP 10 - Axure &#xff08;PS&#xff1a;11都出了&#xff09; 版本&#xff1a;10.0.0.3924 激活码&#xff1a;49bb9513c40444b9bcc3ce49a7a022f9 &#xff08;10/11都可以用&#xff0c;但只尝试了10&#xff…