• 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
    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 ,失败:错误码

    创建线程实例代码如下:
    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <pthread.h>
    4. void* fun(void* arg)
    5. {
    6. int i;
    7. for(i = 0; i < 7; i++){
    8. printf("我是fun\n");
    9. sleep(1);
    10. }
    11. return 0;
    12. }
    13. int main(void)
    14. {
    15. int i;
    16. pthread_t tid;
    17. //fun();
    18. if(pthread_create(&tid,NULL,fun,NULL)){
    19. perror("pthread_create");
    20. exit(1);
    21. }
    22. for(i = 0; i < 7; i++){
    23. printf("我是主函数\n");
    24. sleep(1);
    25. }
    26. return 0;
    27. }
     需要特别注意的是:

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

    -lpthread和-pthread的区别

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

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

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

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

    3.2 给线程函数传参  

    传参实例代码如下:
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <unistd.h>
    4. #include <pthread.h>
    5. typedef struct{
    6. int sno;
    7. char name[20];
    8. float score;
    9. }St;
    10. void* fun(void* arg)
    11. {
    12. St *p = (St*)arg;
    13. //printf("%d\n",*(int*)arg);
    14. //printf("%s\n",(char*)arg);
    15. printf("%d %s %.2f\n",p->sno,p->name,p->score);
    16. return 0;
    17. }
    18. int main(void)
    19. {
    20. pthread_t tid;
    21. //int a = 120;
    22. //char str[] = "hello world";
    23. St s = {1001,"peter",98.56};
    24. if(pthread_create(&tid,NULL,fun,&s)){
    25. perror("pthread_create");
    26. exit(1);
    27. }
    28. sleep(1);
    29. return 0;
    30. }

    3.3 给线程收尸

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

    收尸实例代码如下: 
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <unistd.h>
    4. #include <pthread.h>
    5. typedef struct{
    6. int sno;
    7. char name[20];
    8. float score;
    9. }St;
    10. void* fun(void* arg)
    11. {
    12. static int a = 112200;
    13. St *p = (St*)arg;
    14. //printf("%d\n",*(int*)arg);
    15. //printf("%s\n",(char*)arg);
    16. printf("%d %s %.2f\n",p->sno,p->name,p->score);
    17. return &a;
    18. }
    19. int main(void)
    20. {
    21. pthread_t tid;
    22. int *p;
    23. //int a = 120;
    24. //char str[] = "hello world";
    25. St s = {1001,"peter",98.56};
    26. //创建子线程
    27. if(pthread_create(&tid,NULL,fun,&s)){
    28. perror("pthread_create");
    29. exit(1);
    30. }
    31. //给指定线程收尸,如果子线程没有结束,则主线程阻塞
    32. //if(pthread_join(tid,NULL)){
    33. if(pthread_join(tid,(void**)&p)){
    34. perror("pthread_join");
    35. exit(1);
    36. }
    37. printf("*p = %d\n",*p);
    38. return 0;
    39. }

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

    1.初始化条件休眠

    头文件:#include

    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

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

    3.唤醒线程 

    头文件:#include

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

    4.设置取消状态 

    头文件:#include

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

     5.设置取消方式

    头文件:#include

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

    6.取消线程 

    头文件:#include

     int pthread_cancel (pthread_t __th);

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

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


    总结

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

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

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

  • 相关阅读:
    022python - http请求(理论)
    python中protobuf和json互相转换应用
    基于 FPGA 使用 Verilog 实现 DS18B20 温度采集以及数码管显示项目源码
    单元测试是什么?怎么写?主要测试什么?
    【华为OD机试真题 python】热点网站统计 【2022 Q4 | 200分】
    Qt重启windows服务
    d3dx9_43.dll丢失如何修复?四种快速修复d3dx9_43.dll丢失的方法分享
    RabbitMQ集群搭建详细介绍以及解决搭建过程中的各种问题 + 配置镜像队列——实操型
    面试碰到分布式技术面试题该怎么解答?
    JAVA 字节运算 取低5位 获取低位第一位
  • 原文地址:https://blog.csdn.net/weixin_58070962/article/details/133765391