C/C++ 线程超详细讲解(系统性学习day10)

目录

前言

一、线程基础

1.概念

 2.一个进程中多个线程特征

2.1 线程共有资源

2.2 线程私有资源  

3.线程相关的api函数

 3.1 创建线程

创建线程实例代码如下:

 需要特别注意的是:

-lpthread和-pthread的区别

3.2 给线程函数传参  

传参实例代码如下:

3.3 给线程收尸

收尸实例代码如下: 

 二、线程状态转换函数说明

1.初始化条件休眠

2.条件休眠,挂起线程 

3.唤醒线程 

4.设置取消状态 

 5.设置取消方式

6.取消线程 

三 、线程状态转换图片(如图清晰可见)

总结


前言

线程指的是在一个进程中独立执行的最小单位。简单来说,线程是进程中的一个执行流,可以理解为执行程序的一条执行路径。本篇文章将对线程进行超详细讲解。


一、线程基础

1.概念

(1)线程:在进程空间中执行,也是一个动态的过程。

(2)一个进程对应一个程序,一个线程对应程序中的一个函数

(3)线程是该函数的一次在执行过程,该函数称为线程函数。

 2.一个进程中多个线程特征

2.1 线程共有资源

(1)可执行的指令(.text)
(2)静态数据(.data/.bss/.heap)
(3)进程中打开的文件描述符
(4)信号处理函数
(5)当前工作目录
(6)用户ID
(7)用户组ID

2.2 线程私有资源  

(1)线程ID (TID)
(2)PC(程序计数器)和相关寄存器
(3)堆栈
(4)局部变量
(5)返回地址
(6)错误号 (errno)
(7)信号掩码和优先级
(8)执行状态和属性

3.线程相关的api函数

 3.1 创建线程

头文件:

#include <pthread.h>
Compile and link with -pthread.

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
//参数1 ----- 保存线程id的变量的地址
//参数2 ----- 线程属性,一般为NULL,表示使用默认属性
//参数3 ----- 线程函数指针,必须是下面的格式:
             void * xxx_fun (void * arg)
             {
                     线程执行代码
             }
//参数4  ----- 传给线程函数的参数
//返回值 ---- 成功:0 ,失败:错误码

创建线程实例代码如下:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>void* fun(void* arg)
{int i;for(i = 0; i  < 7; i++){printf("我是fun\n");sleep(1);}return 0;
}int main(void)
{int i;pthread_t tid;//fun();if(pthread_create(&tid,NULL,fun,NULL)){perror("pthread_create");exit(1);}for(i = 0; i  < 7; i++){printf("我是主函数\n");sleep(1);}return 0;
}
 需要特别注意的是:

编译时,需要链接线程库
gcc pthread_create.c -o pthread_create  -lpthread

-lpthread和-pthread的区别

两个选项都是用于链接 pthread 库的选项,但它们有一些细微的差别。

-lpthread 是告诉链接器去链接 pthread 库,这是一个标准的链接选项,可以用于链接任何库。

-pthread 是告诉编译器在编译时需要使用 pthread 库,这是一个非标准的编译选项,只能在支持它的编译器上使用。

在大多数情况下,使用 -lpthread 是更好的选择,因为它是标准的链接选项,可以在不同的编译器和操作系统上使用。而 -pthread 只能在支持它的编译器上使用

3.2 给线程函数传参  

传参实例代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>typedef struct{int sno;char name[20];float score;
}St;void* fun(void* arg)
{St *p = (St*)arg;//printf("%d\n",*(int*)arg);//printf("%s\n",(char*)arg);printf("%d %s %.2f\n",p->sno,p->name,p->score);return 0;
}int main(void)
{pthread_t tid;//int a = 120;//char str[] = "hello world";St s = {1001,"peter",98.56};if(pthread_create(&tid,NULL,fun,&s)){perror("pthread_create");exit(1);}sleep(1);return 0;
}

3.3 给线程收尸

 int pthread_join(pthread_t thread, void **retval);
//参数1 ---- 线程的id
//参数2 ---- 保存线程返回值的指针变量的地址
//返回值 ---- 成功:0,失败:错误码

收尸实例代码如下: 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>typedef struct{int sno;char name[20];float score;
}St;void* fun(void* arg)
{static int a = 112200;St *p = (St*)arg;//printf("%d\n",*(int*)arg);//printf("%s\n",(char*)arg);printf("%d %s %.2f\n",p->sno,p->name,p->score);return &a;
}int main(void)
{pthread_t tid;int *p;//int a = 120;//char str[] = "hello world";St s = {1001,"peter",98.56};//创建子线程if(pthread_create(&tid,NULL,fun,&s)){perror("pthread_create");exit(1);}//给指定线程收尸,如果子线程没有结束,则主线程阻塞//if(pthread_join(tid,NULL)){if(pthread_join(tid,(void**)&p)){perror("pthread_join");exit(1);}printf("*p = %d\n",*p);return 0;
}

 二、线程状态转换函数说明

1.初始化条件休眠

头文件:#include <pthread.h>

int pthread_cond_init (pthread_cond_t * __cond,const pthread_condattr_t * __cond_attr)
 * 功能:初始化条件休眠
 * 参数:
    pthread_cond_t * __cond - 指向被初始化的条件变量
    const pthread_condattr_t * __cond_attr- 指向条件变量的属性,使用默认值NULL
 * 返回值:
    失败:负数,绝对值是错误码

2.条件休眠,挂起线程 

头文件:#include <pthread.h>

int pthread_cond_wait (pthread_cond_t * __cond, pthread_mutex_t *__mutex);
 * 功能:条件休眠,挂起线程(调用该函数的线程被阻塞了,函数不返回,且休眠状态)
 * 参数:
    pthread_cond_t * __cond - 指向条件变量
    pthread_mutex_t *__mutex- 指向互斥锁
 * 返回值:
    失败:负数,绝对值是错误码

3.唤醒线程 

头文件:#include <pthread.h>

int pthread_cond_signal (pthread_cond_t *__cond);
 * 功能:唤醒线程(调用该函数的唤醒被pthread_cond_wait阻塞的线程)
 * 参数:
    pthread_cond_t * __cond - 指向条件变量
 * 返回值:
    失败:负数,绝对值是错误码

4.设置取消状态 

头文件:#include <pthread.h>

int pthread_setcancelstate (int __state, int *__oldstate);
 * 功能:设置取消状态
 * 参数:
    int __state    - 使能还不使能
            使能取消线程,PTHREAD_CANCEL_ENABLE
    int *__oldstate- 保存老状态
 * 返回值:
    失败 - 负数绝对值是错误码

 5.设置取消方式

头文件:#include <pthread.h>

int pthread_setcanceltype (int __type, int *__oldtype);
 * 功能:设置取消方式
 * 参数:
    int __type    - 取消方式
            PTHREAD_CANCEL_ASYNCHRONOUS - 异步取消
            PTHREAD_CANCEL_DEFERRED - 取消延迟
    int *__oldtype- 保存老方式
 * 返回值:
    失败 - 负数绝对值是错误码

6.取消线程 

头文件:#include <pthread.h>

 int pthread_cancel (pthread_t __th);

/*
 * 功能:取消线程
 * 参数:
    pthread_t __th - 线程ID
 * 返回值:
    失败 - 负数绝对值是错误码

三 、线程状态转换图片(如图清晰可见)


总结

        本篇文章针对C/C++ 线程进行详细讲解,希望能够帮到大家!

        以后还会给大家展现更多关于嵌入式和C语言的其他重要的基础知识,感谢大家支持懒大王!

       希望这篇博客能给各位朋友们带来帮助,最后懒大王请来过的朋友们留下你们宝贵的三连以及关注,感谢你们!
 

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

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

相关文章

springboot项目Html页面引入css文件不生效

我的出错原因&#xff1a; 在调用css文件时&#xff1a; <link rel"stylesheet" type"text/css" href"/static/css/style.css" /> 这里我多加了一个/static,而使得css样式不生效 因为在springboot项目中&#xff0c;静态资源是默认存…

3D机器视觉:解锁未来的立体视野

原创 | 文 BFT机器人 机器视觉领域一直在不断演进&#xff0c;从最初的二维图像处理&#xff0c;逐渐扩展到了更复杂的三维领域&#xff0c;形成了3D机器视觉。3D机器视觉技术的涌现为计算机系统带来了全新的感知和理解能力&#xff0c;这一领域的发展正日益受到广泛关注。本文…

上海亚商投顾:沪指探底回升 华为汽车概念股集体大涨

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 三大指数昨日探底回升&#xff0c;早盘一度集体跌超1%&#xff0c;随后震荡回暖&#xff0c;深成指、创业板指…

043:mapboxGL鼠标点击提示source属性信息

第043个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中通过鼠标点击提示source属性信息。这里用到了popup弹窗,用到了click事件,用到了鼠标样式的变化等功能。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源…

Unity设计模式——建造者模式

Product类——产品类&#xff0c;由多个部件组成。 class Product {IList<string> parts new List<string>();//添加产品部件public void Add(string part){parts.Add(part);}public void Show(){foreach (string part in parts){Debug.Log("产品:"pa…

Centos中利用自带的定时器Crontab_实现mysql数据库自动备份_linux中mysql自动备份脚本---Linux运维工作笔记056

这个经常需要,怕出问题因而需要经常备份数据库,可以利用centos自带的定时器,配合脚本实现自动备份. 1.首先查看一下,这个crontab服务有没有打开: 执行:ntsysv 可以看到已经开机自启动了. 注意这个操作界面,用鼠标不行,需要用,tab按键,直接tab到确定,或取消,然后按回车回到命…

【Go】excelize库实现excel导入导出封装(一),自定义导出样式、隔行背景色、自适应行高、动态导出指定列、动态更改表头

前言 最近在学go操作excel&#xff0c;毕竟在web开发里&#xff0c;操作excel是非常非常常见的。这里我选择用 excelize 库来实现操作excel。 为了方便和通用&#xff0c;我们需要把导入导出进行封装&#xff0c;这样以后就可以很方便的拿来用&#xff0c;或者进行扩展。 我参…

软件测试之概念篇(需求,测试用例,BUG描述,产品的生命周期)

目录 1.什么是需求 2.什么是测试用例 3.什么是BUG 4.软件的生命周期 5.测试的生命周期 1.什么是需求 在大多数软件公司&#xff0c;一般会有两部分需求&#xff1a; 用户需求&#xff1a;可以理解为就是甲方提出需求&#xff0c;如果没有甲方&#xff0c;那么就是终端用…

前端项目--尚医通学习分享

这段时间跟着线上课程完成了一个项目&#xff1a;商医通&#xff08;基于Vue3TypeScript的医院挂号平台&#xff09;。具体我就不过多地介绍其具体功能以及详细的实现步骤了&#xff0c;感兴趣的小伙伴直接&#xff1a;传送门 。该文章我就分享一下在该项目中学习到的一些知识点…

Fisher辨别分析

问题要求 在UCI数据集上的Iris和Sonar数据上验证算法的有效性。训练和测试样本有三种方式&#xff08;三选一&#xff09;进行划分&#xff1a; &#xff08;一&#xff09; 将数据随机分训练和测试&#xff0c;多次平均求结果 &#xff08;二&#xff09;K折交叉验证 &…

Session共享问题

出现这个问题的原因&#xff0c;从根本上来说是因为Http协议是无状态的协议。客户端和服务端在某次会话中产生的数据不会被保留下来&#xff0c;所以第⼆次请求服务端无法认识到你曾经来过&#xff0c; Http为什么要设计为无状态协议&#xff1f;早期都是静态页面无所谓有无状态…

UE4和C++ 开发-C++绑定widget的方式和初始化UI

C绑定widget的方式有两种&#xff0c;一种是使用meta (BindWidget)&#xff0c;一种是使用GetWidgetFromName(TEXT("")),两种方式都可以。一、meta BindWidget方式 注意这种绑定的方式UMG里面的空间名称需要与C里面声明的变量名称相同 Btn_StartU 二、GetWidge…