线程的通俗解释

------------------------------------------------------------
author:     hjjdebug
date:       2024年 03月 17日 星期日 17:04:47 CST
descpriton: 线程的通俗解释
------------------------------------------------------------

目录:

1. 什么是线程? 
2. 线程函数长得什么样? 
3. 为什么要使用线程.
4. 线程控制.
 4.0 线程的执行和挂起
 4.1: 线程中的互斥操作
 4.2: 线程中的同步操作
 4.3: 为什么不用全局变量作线程间控制变量?
 4.4: 全局变量在线程同步或互斥中没有立足只地吗?
 4.5: 线程的创建与销毁
 

--------------------
1. 什么是线程? 
--------------------

线程是对象吗? 线程不是对象, 对象是一个数据结构变量,对应一块数据内存.
线程是函数吗? 线程不是普通意义下的函数, 但它也是函数.
线程是代码吗? 线程是代码. 线程执行就是执行线程函数中的代码.

那线程函数与普通函数又有什么区别呢?
线程函数形式上是void* thread_func(void *) 形式.
当该函数被创建线程函数 pthread_create(&threadID, NULL, thread_func, NULL) 引用时, 它就成了线程函数.
线程函数就是被cpu 要调度执行的函数.

通常意义下的函数往往是主线程下的函数, 我们经常书写这样的函数而对它没有感觉.

-----------------------
2. 线程函数长得什么样? 
-----------------------
如下示例.
void * thread_func(void *args)
{
    while(1)
    {
        wait_signal();
        ....
        if(stop) break;
    }
    return NULL;
}

线程函数通常都有一个while循环(或类似于while循环), 因为一旦它退出循环,就意味着线程的终结.


-----------------------
3. 为什么要使用线程.
-----------------------
 因为用线程可以实现并发执行. 提高效率.
 同时还可以有其它一些用途.
 想一想, 原来是一个人干活, 现在能n个人干活, 是不是很兴奋呢!
 例如: 蚂蚁下载, 下载一个大文件,一只蚂蚁要下很长时间, n只蚂蚁把大文件分成n块协同下载,很快就下载完成了.


-----------------------
 4. 线程控制.
-----------------------
 一个线程相当于一个人,多个线程相当于多个人.
 一个人可以有条不紊的按先后次序干活, 多个人就必需要分工协作,否则就会乱套.

-----------------------
 4.0 线程的执行和挂起
-----------------------
 当要执行一个线程时,一个重要的概念是它应该被执行还是应该休息. 
 当条件满足时,它应该被执行,
 当条件不满足时,它应该被挂起.
 用代码来表示:
 if(ready)  // 条件ready
 {
     running;  //线程被执行
 }
 else
 {
     sleep;   // 线程被挂起
 }
  
-----------------------
4.1: 线程中的互斥操作
-----------------------
  其本质是只有一个线程在运行敏感代码,其余线程运行到此处都会被挂起.
  在线程控制中, 用全局变量有很多毛病(一会讲清), 而应该用操作系统原语. 就是说应该用操作系统给你提供的变量.
  其中之一是互斥变量mutex , 互斥变量主要是用来实现线程间的代码互斥.
  线程互斥量的典型用法:
  Mutex v_mutex; // 声明一个Mutex 变量 v_mutex
  v_mutex.lock() // 要进入敏感代码,先申请锁,申请到了我就执行, 申请不到就让我sleep.
  critical_code();  //保证这块代码仅有一个线程可以执行
  v_mutex.unlock(); //代码执行完要释放锁, 这样别的线程才可能得到资源来执行这块代码

-----------------------
4.2: 线程中的同步操作
-----------------------
  其本质还是线程的运行和挂起来完成. 得不到资源的被挂起实现执行顺序.
  线程的同步原语是sem_t; 
  其典型用法是:
  sem_t v_sem; //semphore 就是一个计数器.
  sem_init(&v_sem,0,1); //第2个参数0表示它不是进程共享,而是线程共享,第3个参数表示semphore的初始值

  sem_wait(&v_sem); //申请一个资源, 申请到了执行,申请不到资源会被挂起.
  sem_post(&v_sem); //释放一个资源
  申请资源相当于P操作,释放资源相当于V操作, 这就是典型的共享资源的PV操作.

  线程同步典型的例子就是生产者,消费者的例子. 生产者一定要在消费者的前面执行.
  同样,医生作手术次序也很重要, 
  第一步,把病人抬上手术台. 
  第二步,把手术刀放到医生手上.
  第三步,医生开始做手术.

  次序错了或者缺了哪一步, 那医生还做个鬼啊!

----------------------------------------
4.3: 为什么不用全局变量作线程间控制变量?
----------------------------------------
  说实话, 互斥量就是一个布尔值, 信号量就是一个整形值(给1也能起互斥量的作用), 用全局变量不可以替代吗?
  不可以,主要是因为对全局变量的操作不是原子操作, 所谓原子操作就是一口气干完, 从汇编的角度看,有时候甚至
  关闭中断, 专门干你那点活,然后再开中断. 总之就是保证不被打扰的意思.
  举个火车站售票的例子吧, 当你要满G158 石家庄到北京车票,车票还有一张, 此时另一个窗口也有一个顾客买G158车票石家庄到北京
  用全局变量
  if(tick_count>0)
  {
   tick_count--;
  }
 你这个线程看到tick_count 为1, 你付款了,当你把tick_count 变量拿起来,准备减1时,线程被切换走了.
 另一个窗口的线程也看到了tick_count=1, 所以它把票卖走了, 线程又切回到你这里,你继续执行减1,你也拿到了最后这张票.
 问题出在哪? 一张票卖给了2个人! 就在于这个tick_count--不是原子操作, 还没有干好呢,被切换走了.
 如果用set_t 就不会有这种事.
 sem_wait(sem_count); // 拿到了这个资源, 你就可以干你的事,拿不到,线程就被挂起来了,不会出现竞争.


------------------------------------------------
 4.4: 全局变量在线程同步或互斥中没有立足只地吗?
------------------------------------------------
 也不是, 它只能做简单的同步与互斥操作, 不会被线程同时操作到的那一种.
 例如: 象棋对弈,红先黑后,轮流行棋. 只有2个线程,
 初始化: red_flag=1, black_flag=0;
 红棋:
 while(1)
 {
     if(red_flag)
     {
       行棋;
       red_flag=0;   //之所以可以用全局变量,是因为对red_flag,black_flag 的操作
       black_flag=1; // 两个线程根本不可能同时操作到同一个变量. 因为红方在操作时,黑方在睡眠
     }                // 同理,黑方在操作者两个变量时,红方在睡眠,所以不会引起冲突!
     else
     {
      sleep(1);
     }
  }
 黑棋:
 while(1)
 {
     if(black_flag)
     {
       行棋;
       black_flag=0;
       red_flag=1;
     }
     else
     {
      sleep(1);
     }
  }
用semophore 有更优雅的表现方式.
sem_t red,black;
sem_init(red,0,1);
sem_init(black,0,0);
红棋:
 while(1)
 {
   sem_wait(red);  //申请资源
   行棋;
   sem_post(black); //释放黑方资源
  }

 黑棋:
 while(1)
 {
   sem_wait(black); //申请资源
   行棋;
   sem_post(red);  //释放红方资源.
 }

-----------------------
4.5: 线程的创建与销毁
-----------------------
  线程创建: 可创建thread_func 线程
  pthread_create(&threadID, NULL, thread_func, NULL);
  线程销毁:  
    1. thread_func, 退出循环,即可自动销毁. return 返回值做为线程返回值
    2. 线程函数中调用thread_exit(val); 来退出, 与return val 一致
    3. 千万不要调用exit(val), 这样不只该线程, 所有线程即整个进程都退出了!
      4. pthread_cancel(threadID), 从别的线程中强制销毁该线程

  说明: 这个threadID 是一个内存地址, unsigned long 类型, 不是linux内核中的threadid
     它的数值等于pthread_self(), 属于pthread 概念范畴.
     用ps -p pid -T 显示的是linux 内核中的threadid, 代码中可以用gettid()函数得到

  有时候, 一个线程由于其特殊性不能销毁, 但需要它处于一个已知的可控的状态,
  此时可以使用全局变量,控制线程的循环,当发现变量为真时,就进入sleep状态
  并返回一个已进入sleep 标志, 这样外部程序知道它没有执行敏感代码,
  从而可以执行一些敏感操作. 然后再放开控制变量,这样当线程醒来并可执行时,
  环境已经更新. 这个操作,等价于销毁,重建.
 

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

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

相关文章

EMQX 4.0和EMQX 5.0集群架构实现1亿MQTT连接哪些改进

EMQX 5.0水平扩展能力得到了指数级提升,能够更可靠地承载更大规模的物联网设备连接量。 在EMQX5.0正式发布前的性能测试中,我们通过一个23节点的EMQX集群,全球首个达成了1亿MQTT连接每秒100万消息吞吐,这也使得EMQX 5.0成为目前为…

Jenkins流水线将制品发布到Nexus存储库

1、安装jenkins(建议别用docker安装,坑太多) docker run -d -p 8089:8080 -p 10241:50000 -v /var/jenkins_workspace:/var/jenkins_home -v /etc/localtime:/etc/localtime --name my_jenkins --userroot jenkins/jenkins:2.449 坑1 打开x…

Python使用 k 均值对遥感图像进行语义分割

本篇文章介绍K-means语义分割来估计 2000 年至 2023 年咸海水面的变化 让我们先看一下本教程中将使用的数据。这是同一地区的两张 RGB 图像,间隔 23 年,但很明显地表特性和大气条件(云、气溶胶等)不同。这就是为什么我决定训练两个独立的 k-Means 模型,每个图像一个。 首…

仰卧起坐计数,YOLOV8POSE

仰卧起坐计数,YOLOV8POSE 通过计算膝盖、腰部、肩部的夹角,计算仰卧起坐的次数

JavaScript爬虫进阶攻略:从网页采集到数据可视化

在当今数字化世界中,数据是至关重要的资产,而网页则是一个巨大的数据源。JavaScript作为一种强大的前端编程语言,不仅能够为网页增添交互性,还可以用于网页爬取和数据处理。本文将带你深入探索JavaScript爬虫技术的进阶应用&#…

[江苏工匠杯]easyphp

先看源码 <?php highlight_file(__FILE__); $key1 0; $key2 0; ​ $a $_GET[a]; $b $_GET[b]; ​ if(isset($a) && intval($a) > 6000000 && strlen($a) < 3){if(isset($b) && 8b184b substr(md5($b),-6,6)){$key1 1;}else{die("…

centos8作为虚拟机镜像时yum报错

使用yum安装时出现如下错误&#xff1a; Errors during downloading metadata for repository AppStream:- Status code: 404 for http://mirrors.cloud.aliyuncs.com/centos/8/AppStream/x86_64/os/repodata/repomd.xml (IP: 100.100.2.148) Error: Failed to download metad…

助力企业跨越地域限制,实现业务全球化与数字化升级

驱动跨行业数字化转型与全球化互联实践》 中国联通作为中国领先的电信运营商&#xff0c;在物联网领域不断创新&#xff0c;尤其在跨境物联网产品解决方案上取得了显著成果&#xff0c;已经成功服务于各行各业&#xff0c;实现了全球化业务的有效链接与智能化管理。以下将详述…

Day19 包装类 Integer底层

Day19 包装类 Integer底层 一、包装类 1、概念&#xff1a; 包装类&#xff08;Wrapper Class&#xff09;是一种用于将基本数据类型转换为对象的类。Java中的基本数据类型&#xff08;如int、char、boolean等&#xff09;是非对象的&#xff0c;为了能够在需要对象的上下文中…

mvn 相关命令汇总

1、需求 项目上一致是使用的mvn 进行打包, 对于项目上的一些mvn 命令&#xff0c;有时候会忘记&#xff0c;所以将mvn 汇总起来 2、命令汇总 ① mvn clean 将项目目录下的编译的文件清除掉,即target 文件夹的编译文件 ② mvn complie 编译项目的代码&#xff0c;生成class 文…

Spring boot2.7整合jetcache方法缓存

前面的文章 我们讲了 spring boot 整合 jetcache 做基本字符串数据缓存 但是 我这里有个这样的逻辑 我的 domain 包下 有一个 book 属性类 里面就 id 和 name 属性 设置了 对应的 set get函数 和一个整体的构造函数 package com.example.javadom.domain;public class book {pr…

TrueNAS怎么设置中文,最新2024版本安装详细说明

首先我们做好安装前的准备工作 1&#xff0c;ISO镜像安装包 2&#xff0c;虚拟机&#xff08;建议使用ESXI虚拟机环境&#xff09; 如果是物理机安装&#xff0c;建议先给底层安装虚拟机系统esxi&#xff0c;再在上面安装方便以后的管理&#xff0c;如果你想物理机直接安装&a…

3.15消费者权益保护教育宣传活动怎样联系媒体投稿宣传?

在315金融消费者权益保护教育宣传活动中,想要有效地联系媒体报道并进行便捷宣传,可以通过以下步骤来利用智慧软文发布系统进行操作: 1. 准备宣传素材: - 制作高质量的新闻稿件,内容应围绕金融消费者权益保护的主题,包含活动的目的、特色、实施计划、预期影响、参与方式等细节;…

怎么看一手伦敦银多少钱?

做伦敦银投资的朋友需要搞清楚“一手伦敦银多少钱”的问题&#xff0c;这也是伦敦银交易的基础问题。为什么需要搞清楚这个基础问题呢&#xff1f;有些基础问题我们不需要搞懂&#xff0c;但是关于一手伦敦银多少钱却需要搞清楚&#xff0c;因为这决定了投资者的资金利用率。 关…

复合材料热压机比例阀放大器

复合材料热压机动作主要依赖于其内置的液压系统。是工业生产中常用的设备&#xff0c;通过施加高温和高压来实现对材料的压制成型。为了确保热压板能够精确地上下移动以及保持所需的压力&#xff0c;通常会使用液压系统来控制。液压系统中必不可少的需要比例阀来控制油缸的运行…

二进制1的个数(c++题解)

题目描述 统计一个十进制数中二进制1的个数 输入格式 一个int范围内的整数&#xff08;可能为负数&#xff09;。 输出格式 二进制1的个数。 样例 样例输入 复制2样例输出 复制1数据范围与提示 CPU是32位处理器 __________________________________________________…

0105行列式按行(列)展开-行列式-线性代数

在n阶行列式中&#xff0c;把 ( i , j ) 元 a i j (i,j)元a_{ij} (i,j)元aij​所在的第 i 行和第 j i行和第j i行和第j列划去后&#xff0c;留下来的 n − 1 n-1 n−1阶行列式叫做 ( i , j ) 元 a i j (i,j)元a_{ij} (i,j)元aij​的余子式&#xff0c;记作 M i j M_{ij} Mij​&…

APP内嵌微信H5支付完成后跳转浏览器问题如何解决

大家好我是咕噜美乐蒂&#xff0c;很高兴又和大家见面了&#xff01; 在App内嵌微信H5支付完成后跳转到浏览器的场景中&#xff0c;涉及到了跨平台交互和支付流程的处理。这种情况通常会涉及到用户在微信H5支付页面完成支付后需要跳转到浏览器来展示支付结果或其他相关信息。以…

ReentrantLock的实现原理

ReentrantLock 是 Java 中的一个高级同步机制&#xff0c;它提供了比传统的 synchronized 方法和语句更灵活的锁定操作。ReentrantLock 实现了 Lock 接口&#xff0c;并且完全依赖于 AbstractQueuedSynchronizer (AQS) 的扩展来实现其同步行为。 ReentrantLock 特性 可重入: …

【数字孪生】Nginx发布数字孪生三维建模模型服务及调用方法

【数字孪生】Nginx发布数字孪生三维建模模型服务及调用方法 一、需求二、实施步骤2.1 准备模型文件2.1.1 3D tiles模型2.1.2 3D Tiles标准文件格式 2.2 配置nginx server块2.2.1 Nginx能干啥 2.3 访问 三、实现效果 一、需求 利用三维渲染引擎Cesium加载3D tiles模型。 二、实…