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

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

前言

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


一、线程基础

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语言的其他重要的基础知识,感谢大家支持懒大王! 

相关文章
|
5天前
|
算法 网络安全 区块链
2023/11/10学习记录-C/C++对称分组加密DES
本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。
24 4
2023/11/10学习记录-C/C++对称分组加密DES
|
1月前
|
缓存 安全 C++
C++无锁队列:解锁多线程编程新境界
【10月更文挑战第27天】
49 7
|
1月前
|
消息中间件 存储 安全
|
2月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
58 1
C++ 多线程之初识多线程
|
2月前
|
存储 并行计算 安全
C++多线程应用
【10月更文挑战第29天】C++ 中的多线程应用广泛,常见场景包括并行计算、网络编程中的并发服务器和图形用户界面(GUI)应用。通过多线程可以显著提升计算速度和响应能力。示例代码展示了如何使用 `pthread` 库创建和管理线程。注意事项包括数据同步与互斥、线程间通信和线程安全的类设计,以确保程序的正确性和稳定性。
|
2月前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
2月前
|
监控 安全 算法
线程死循环确实是多线程编程中的一个常见问题,它可能导致应用程序性能下降,甚至使整个系统变得不稳定。
线程死循环是多线程编程中常见的问题,可能导致性能下降或系统不稳定。通过代码审查、静态分析、日志监控、设置超时、使用锁机制、测试、选择线程安全的数据结构、限制线程数、使用现代并发库及培训,可有效预防和解决死循环问题。
74 1
|
2月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
79 6
|
2月前
|
监控 安全 算法
线程死循环是多线程编程中的常见问题,可能导致应用性能下降甚至系统不稳定。
【10月更文挑战第6天】线程死循环是多线程编程中的常见问题,可能导致应用性能下降甚至系统不稳定。为了解决这一问题,可以通过代码审查、静态分析、添加日志监控、设置超时机制、使用锁和同步机制、进行全面测试、选用线程安全的数据结构、限制线程数量、利用现代并发库,并对团队进行培训等方法来预防和减少死循环的发生。尽管如此,多线程编程的复杂性仍需要持续监控和维护以确保系统稳定。
65 3
|
2月前
|
缓存 负载均衡 Java
c++写高性能的任务流线程池(万字详解!)
本文介绍了一种高性能的任务流线程池设计,涵盖多种优化机制。首先介绍了Work Steal机制,通过任务偷窃提高资源利用率。接着讨论了优先级任务,使不同优先级的任务得到合理调度。然后提出了缓存机制,通过环形缓存队列提升程序负载能力。Local Thread机制则通过预先创建线程减少创建和销毁线程的开销。Lock Free机制进一步减少了锁的竞争。容量动态调整机制根据任务负载动态调整线程数量。批量处理机制提高了任务处理效率。此外,还介绍了负载均衡、避免等待、预测优化、减少复制等策略。最后,任务组的设计便于管理和复用多任务。整体设计旨在提升线程池的性能和稳定性。
84 5