线程的基本概念,线程的同步互斥机制

2023-11-08

一、线程的概念

1 .1 什么是线程

        线程:线程是进程的一个实体,是被系统独立调度和分派的基本单位,是一个进程并发执行多个任务的机制。

        并发:单核CPU多任务同时运行,CPU以ms级进行进程调度

1.2 为什么引入线程

        进程间的切换表现为上下文的切换:

        上下文:运行一个进程所需要的所有资源

        上下文切换:从访问进程1到访问进程2,CPU访问的资源要替换原有内容,这个操作本身是一个耗时操作

        为了减少进程创建、撤销和切换时所付出的时空开销,使操作系统有更好的并发性,把资源的分配单位和调度单位分开,提出了线程。

        线程属于进程,每一个进程至少有一个线程作为指令执行体,线程运行在进程空间内,一个进程中可以有多个线程,因此程序也被称为多线程程序。

1.3 进程与线程的区别 

  1. 进程是资源分配的最小单位,线程是任务运行的最小单位!!!
  2. 进程与进程的用户空间相互独立,内核空间是所有进程共享,进程与进程之间的通信,需要引入进程间通信机制才能实现
  3. 线程与线程共享其附属进程的所有资源,线程运行在进程空间内,线程与线程之间的通信,需要注意同步互斥
  4. 创建多线程的效率比创建多进程高
  5. 多进程的资源量比多线程高
  6. 多进程稳定性比多线程高

二、线程的相关函数

2.1 pthread_create

 功能:创建一个线程

函数原型:

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

 参数:

        pthread_t *thread:存储创建后的线程id号

        pthread_attr_t *attr:线程的属性,填NULL。如果要设置,该位置需要通过pthread_attr_init初始化属性,可以设置分离属性              void *(*start_routine) (void *):函数指针,该指针指向线程的任务执行体。该指针可以指向返回值是void*类型,参数列表是void*类型的函数,例如:void* callBack(void* arg){}

        void *arg:传递给函数指针指向的函数的参数

返回值:

        成功,返回0

        失败,返回错误编号,即非0

2.1.1 注意事项: 

  1. 从主函数(main())进来的线程称为主线程,pthread_create创建的线程称之为分支线程或子线程
  2. 一般来说,主线程会先运行,但实际运行情况需要按照时间片轮询机制
  3. 主线程退出后(main()函数退出),会导致进程结束,依附于该进程内的所有线程均会被强制退出
  4. 分支线程退出不会影响主线程

 2.1.2 线程的传参

        定义一个全局变量,int a = 10,主线程和分支线程均能访问到,访问到的资源为同一份资源(即临界资源)

        在主线程定义一个局部变量,int b = 10,分支线程不能访问,同样,在分支线程定义一个局部变量,int c = 10,主线程不能访问。因为局部变量的生命周期以及作用域有限,那么如何实现这些资源的共享?

        1)主线程传参给分支线程

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

//线程执行体
void* callBack(void* arg)   //void* arg = &c
{
    while(1)
    {
        printf("this is other func c=%d %p __%d__\n", *(int *)arg, arg,__LINE__);                    
        sleep(1);
    }

    return NULL;
}


int main(int argc, const char *argv[])
{
    //主线程定义一个局部变量
    int c = 10;
    //创建线程
    pthread_t tid;
    if(pthread_create(&tid, NULL, callBack, &c) != 0)
    {
        fprintf(stderr, "pthread_create failed __%d__\n", __LINE__);
        return -1;
    }

    while(1)
    {
        printf("this is main function c=%d %p __%d__\n", c, &c, __LINE__);
        sleep(1);
    }

    return 0;
}

        2)分支线程传承给主线程 

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

//线程执行体
void* callBack(void* arg)   //void* arg = &c
{
    //分支线程定义一个局部变量
    int b = 10;
    *(int *)arg = &b;
    while(1)
    {
        printf("this is other func b=%d %p __%d__\n", b, &b,__LINE__);                    
        sleep(1);
    }

    return NULL;
}


int main(int argc, const char *argv[])
{
    int get_b;
    //创建线程
    pthread_t tid;
    if(pthread_create(&tid, NULL, callBack, &get_b) != 0)
    {
        fprintf(stderr, "pthread_create failed __%d__\n", __LINE__);
        return -1;
    }

    while(1)
    {
        printf("this is main function b=%d %p __%d__\n", get_b, &get_b, __LINE__);
        sleep(1);
    }

    return 0;
}

此时,主线程与分支线程打印的变量,值相等,地址不相等,若想它们的地址也相等我们可以用以下方法:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

//线程执行体
void* callBack(void* arg)   //void* arg = &c
{
    //分支线程定义一个局部变量
    int b = 10;
    *(int **)arg = &b;
    while(1)
    {
        printf("this is other func b=%d %p __%d__\n", b, &b,__LINE__);                    
        sleep(1);
    }

    return NULL;
}


int main(int argc, const char *argv[])
{
    int *get_b = NULL;
    //创建线程
    pthread_t tid;
    if(pthread_create(&tid, NULL, callBack, &get_b) != 0)
    {
        fprintf(stderr, "pthread_create failed __%d__\n", __LINE__);
        return -1;
    }

    while(1)
    {
        printf("this is main function b=%d %p __%d__\n", *get_b, get_b, __LINE__);
        sleep(1);
    }

    return 0;
}

2.2 pthread_exit 

功能:退出线程,并传递线程退出状态值,线程退出后,会残留一部分资源,该资源可以被pthread_join回收

函数原型:

#include <pthread.h> 
void pthread_exit(void *retval);

参数:

        void *retval:可以传递线程退出状态值,可以是任意类型数据;。数据会被pthread_join函数接收。参数可以填NULL,代表不返回任何数据

2.3 pthread_join

功能:阻塞函数,阻塞等待指定的线程退出。 线程退出后,会残留一部分资源,该资源可以被pthread_join回收

函数原型:

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

参数:

        pthread_t thread:指定要等待、回收哪一个线程的资源; void **retval:如果该参数不为NULL,则线程退出状态值会被拷贝到,当前指针指向的内存空间中。 填NULL,代表不接收退出状态值

返回值:

        成功,返回0

        失败,返回错误码,即非0

2.4 pthread_detach

功能:分离线程,线程退出后,由内核自动回收资源。不需要其他线程再调用pthread_join回收。当主线程有自己任务的时候,无法用pthread_join回收线程资源时,选择pthread_detach函数,自动回收资源

函数原型:

#include <pthread.h> 
int pthread_detach(pthread_t thread);

参数:

        pthread_t thread:指定要分离的线程的tid号

返回值:

        成功,返回0

        失败,返回错误码,即非0

注意:当使用pthread_detach分离指定线程后,pthread_join函数将无法回收该线程资源,且pthread_join函数不再阻塞

2.5 pthread_cancel

功能:用一个线程请求另外一个指定线程退出,请求成功,不代表目标线程一定会退出

函数原型:

#include <pthread.h> 
int pthread_cancel(pthread_t thread);

参数:

         pthread_t thread:指定要请求哪个线程退出,填对应的tid号

返回值:

        成功,返回0

        失败,返回错误码,即非0

注意事项:

  1. pthread_cancel会给目标线程打上一个退出标签,CPU切换到目标线程后运行退出标签才能退出线程。
  2. while循环、for循环等循环结构,以及算术运算等位置,无法打上退出标识,因此使用pthread_cancel函数无法退出线程
  3. printf、sleep等需要耗时操作的函数可以打上退出标识
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

线程的基本概念,线程的同步互斥机制 的相关文章

随机推荐

  • Hyperledger Fabric1.0架构概览

    Hyperledger是被业界非常看到的联盟链的实现 包括IBM Intel R3 各个大型商业银行等都参与其中 带给我们关于区块链技术与软件工业 金融 保险 物流等领域碰撞结合的想象空间 在这个联盟中 有超过1 4的成员都来自中国 这更是
  • java虚拟机运行时分布区域

    概述 本文将从概念上介绍java虚拟机内存的各个区域 讲解这些区域的作用 服务对象以及其中可能产生的问题 运行时数据区域 java虚拟机所管理的内存将会包括以下几个运行时数据区域 程序计数器 程序计数器是一块较小的内存空间 它可以看作是当前
  • 动态规划之二维0-1背包问题(思考分析、解决、算法模板)

    一 问题描述 二维费用的背包问题是指对于每件物品 具有两种不同的费用 选择这件物品必须同时付出这两种代价 对于每种代价都有一个可付出的最大值 背包容量 求选择物品可以得到最大的价值 设第i件物品所需的两种代价分别为v i 和u i 两种代价
  • SiT9102:1-220MHz任意频率差分晶振,LVPECL/LVDS/HSCL/CML

    1 SiT9102简介 SiT9102差分晶振是1 220MHz之间任意频点 抖动 lt 1ps 输出支持LVDS LVPECL CML HCSL的高性能差分振荡器 频率稳定度高达 10ppm SiT9102得到了以XiLinx 为代表的主
  • 数据预处理之缺失值

    目录 0 前言 1 缺失值的识别 1 1 每个数据的识别 isnull 1 2 每列 行是否包含缺失值 isnull any isnull all 1 3 缺失值的个数 isnull sum 1 4 检查所有的数据 data info 1
  • C++ 泛型编程(四) 类模板

    前文回顾 C 泛型编程 一 基本概念 C 泛型编程 二 函数模版 C 泛型编程 三 模版实参推断 类模版 定义 定义 类模版是用来生成类的蓝图的 类似函数模版的定义 类模板以关键字 template 开始 后跟尖括号包围的模版参数列表 用关
  • jQuery仿QQ空间图片查看特效(全屏,放大,缩小,旋转,镜像,鼠标滚轮缩放)...

    地址 http www tuicool com articles 2YRVr2a 可以通过nmp或bower来安装该图片查看器插件 npm install imageviewer bower install imageviewer 复制代码
  • 关于kafka——幂等性

    怎么保证幂等性 幂等性 通俗点说 就一个数据 或者一个请求 给你重复来多次 你得确保对应的数据是不会改变的 不能出错 从业务层面考虑 比如你拿个数据要写库 你先根据主键查一下 如果这数据都有了 你就别插入了 update 一下好吧 比如你是
  • 服务器系统盘预留空间,固态硬盘的系统盘需要预留多空间?固态硬盘适不适合分区...

    固态硬盘的对于电脑的提速显而易见 再加少价格降成了萝卜价 所以固态硬盘成为绝大多数人的标配 对于固态硬盘的使用人们也是众说一词 有的人认为固态硬盘不宜多分区 会影响速度 有的人认为固态硬盘和机械硬盘的使用一样 没什么区别 关于这条 我们额外
  • vue 全局过滤器 时间格式 转换

    vue 项目要求将时间戳转成规定的时间格式 可以借助 moment js 完成 现要确定自己的数据是时间戳 安装命令 npm install moment save main js import moment from moment 设置过
  • Oracle日期格式yyyymmdd格式化为yyyy-mm-dd

    问题 日期展示为20200828需要展示为2020 08 28 解决 select TO CHAR TO DATE 20200828 yyyyMMdd YYYY MM DD FKDAT from dual 结果展示 2020 08 28
  • Docker安装Nginx+FTP访问静态资源

    1 拉取Nginx镜像 docker pull nginx latest 2 创建挂载目录 mkdir p server nginx conf mkdir p server nginx log mkdir p server nginx ht
  • 安装Ubuntu的注意事项

    安装win10 Ubuntu elemengtory OS直接进入win10而不出现linnux引导的问题 1 进入BIOS 启动UEFI 关闭Security 2 分区时应该注意的事项 1 swap 2000MB 主分区引导 起始 2 E
  • Pandas 缺失号

    三种缺失符号及其对比 pandas 1 0之前 三种记号 pandas 1 0 np nan None np NaT 时间序列用 类型 float64 Nonetype pandas libs tslibs nattype NaTType
  • mybatis 拼接动态表名、字段名

    转载地址 https blog csdn net xiaoxiangzi520 article details 76719098 今天在项目中遇到个需求是要动态的根据前台传入的字段名称和升降序条件在mybatis里动态拼接sql语句进行查询
  • Java类成员变量的默认值

    1 布尔型 boolean 变量默认值为false byte short int long为0 字符型为 u0000 空字符 浮点型 float double 为0 0 引用类型 String 为null package cn nxl201
  • shell算数运算

    i j k 等价于 i expr j k i j k 等价于 i expr j k i j k 等价于 i expr j k i j k 等价于 i expr j k Let expressions 执行一个或多个表达式 表达式中的变量前不
  • 量化投资学习-15:散户与庄家共赢策略之价值长线策略

    散户的尴尬 在前面的文章 量化投资学习 13 一张图残酷的展现了庄家 量化交易者 散户的盈利空间的对比 中分析过 如果散户追求短期利益 采用短期炒作的操作策略 实际的利润空间非常狭小 只能是尾部或头部空间 稍不留神 就会导致亏损 化解尴尬的
  • 微信小程序接入微信支付(四):接收支付结果通知与沙箱测试

    代码主体写完后 还有不可或缺的部分需要补充完整 即接收支付结果通知 官方文档 https pay weixin qq com wiki doc api wxa wxa api php chapter 9 7 index 8 目录 微信小程序
  • 线程的基本概念,线程的同步互斥机制

    一 线程的概念 1 1 什么是线程 线程 线程是进程的一个实体 是被系统独立调度和分派的基本单位 是一个进程并发执行多个任务的机制 并发 单核CPU多任务同时运行 CPU以ms级进行进程调度 1 2 为什么引入线程 进程间的切换表现为上下文