当前位置: 首页 > news >正文

linux c语言进阶 - 线程,通信方式,安全方式(多并发)

线程

1. 概念

线程是程序中执行的最小单位,它属于进程的一部分。每个进程至少包含一个线程(主线程)。线程共享进程的资源(如内存空间、文件描述符等),但每个线程有自己的堆栈、程序计数器等。多线程编程允许程序在同一时间并行执行多个任务。

1.1 线程与进程的区别

  • 进程操作系统进行资源分配和调度的基本单位,每个进程有独立的内存空间(4G)。

  • 线程程序执行的基本单位,是在进程内运行的独立执行流。线程之间共享进程的内存空间、打开的文件、信号量等资源。

1.2 线程的作用 

1. 并发执行:在多核cpu的下,可以通知执行多个线程,效率高。 比如16核,那可以通过调度16个线程(多个进程)

2. 异步执行: 不用同步执行。**等会写代码来测试。**

2. 线程的使用

2.1 线程的创建

pthread_create() 函数用于创建一个线程。

int pthread_create(pthread_t *tip, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

参数:

    1. thread : 线程 ID 变量指针
    2. attr : 线程属性,默认属性可设置为 NULL
    3. start_routine : 线程执行函数
    4. arg : 线程执行函数的参数

返回值:

    成功 : 返回 0
    失败 : 返回 错误码

注意:

    一旦子线程创建成功,则会被独立调度执行,并且与其他线程 并发执行
创建多个线程时,⼀般由主线程统⼀创建,并等待释放资源或者分离线程, 不要递归创建。
在编译时需要链接 -lpthread

task.json(要修改编译语句)

"args": ["-fdiagnostics-color=always","-g","${file}","-o","${fileDirname}/${fileBasenameNoExtension}","-lpthread"],
  • pthread_t 是线程的标识符。

  • thread_function 是线程的执行函数。

  • pthread_join() 用于等待线程的结束。

int pthread_join(pthread_t thread, void **retval);

参数
    thread : 线程 ID
    retval : 获取线程退出值的指针

返回值
    成功 : 返回 0
    失败 : 返回 错误码

注意

    线程分离函数不会阻塞线程的执行

  • pthread_exit()退出

void pthread_exit(void *retval);

参数:

  retval : 线程返回值,通过指针传递

返回值:

    成功 :返回 0
    失败 : 返回 -1

注意:

 1.当主线程调用 pthread_exit 函数时,进程不会结束,也不会导致其他子线程退出
 2.任何线程调用 exit 函数会让进程结束

 3.在线程函数内部显式调用 `pthread_exit()退出线程。
 4.可以用于线程任意位置退出(不一定要在函数末尾)。

#include <stdio.h>
#include <pthread.h>void *demo(void *arg)
{printf("子线程!\n");return NULL;
}/*线程*/
int main(int argc, char const *argv[])
{// 创建一个pthread_t tid;pthread_create(&tid, NULL, demo, NULL);pthread_join(tid, NULL);return 0;
}

2.2 线程的生命周期

线程的生命周期分为以下几个阶段:

  1. 创建阶段:调用 pthread_create() 创建线程。

  2. 执行阶段:线程开始执行它的任务,执行完线程函数后线程自动终止。

  3. 终止阶段:线程执行完成后会通过 pthread_exit() 或返回函数退出,终止其生命周期。

  4. 等待阶段:线程通过 pthread_join() 被主线程或其他线程等待直到完成。

  5. 清理阶段:线程退出时会自动进行清理,释放资源。

2.3 线程的销毁

  • 自动销毁:线程结束时,系统会回收资源。

  • 手动销毁:使用 pthread_cancel() 可以取消线程,但这需要特别小心,避免线程处于不确定状态。

3. 线程间的通讯(信号,信道,消息队列,共享内存,信号量)

linux c语言进阶 - 进程,通信方式-CSDN博客此文章介绍了一些进程的相关方法,需要的同志可以看一下。

3.1 共享内存

由于线程共享进程的内存空间,它们可以直接通过共享内存进行通信。不同线程可以修改共享变量或数据结构。但这也引发了 线程安全 的问题。

3.2 条件变量(Condition Variable)

条件变量是一种线程同步机制,用于在某个条件满足时唤醒线程。条件变量常与互斥锁一起使用。

#include <pthread.h>
#include <stdio.h>pthread_mutex_t mutex;
pthread_cond_t cond;void *thread_function(void *arg) {pthread_mutex_lock(&mutex);pthread_cond_wait(&cond, &mutex); // 等待条件变量printf("Condition met, thread proceeding\n");pthread_mutex_unlock(&mutex);return NULL;
}int main() {pthread_t thread_id;pthread_mutex_init(&mutex, NULL);pthread_cond_init(&cond, NULL);pthread_create(&thread_id, NULL, thread_function, NULL);// 模拟条件满足pthread_mutex_lock(&mutex);pthread_cond_signal(&cond); // 唤醒等待的线程pthread_mutex_unlock(&mutex);pthread_join(thread_id, NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);return 0;
}

3.3 信号量(Semaphore)

信号量是另一种线程同步机制,通常用于控制多个线程访问共享资源的数量。(有名无名)

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>#define NUM_THREADS 4
#define TOTAL_TICKETS 1000int ticket_count = TOTAL_TICKETS;
sem_t semaphore;void* sell_tickets(void* arg) {while (1) {sem_wait(&semaphore); // 获取信号量if (ticket_count <= 0) {sem_post(&semaphore); // 释放信号量break;}// 模拟售票处理时间struct timespec sleep_time = {0, 1000000}; // 1毫秒nanosleep(&sleep_time, NULL);printf("线程%ld卖出第%d张票\n", (long)arg, ticket_count);ticket_count--;sem_post(&semaphore); // 释放信号量}return NULL;
}int main() {pthread_t threads[NUM_THREADS];sem_init(&semaphore, 0, 1); // 初始值为1的二进制信号量// 创建售票线程for (long i = 0; i < NUM_THREADS; i++) {pthread_create(&threads[i], NULL, sell_tickets, (void*)i);}// 等待所有线程完成for (int i = 0; i < NUM_THREADS; i++) {pthread_join(threads[i], NULL);}sem_destroy(&semaphore);printf("所有票已售罄\n");return 0;
}

3.4 互斥锁(Mutex)

互斥锁用于保护共享资源,避免多个线程同时访问共享资源,从而导致数据不一致。

#include <stdio.h>
#include <pthread.h>#define NUM_THREADS 4
#define TOTAL_TICKETS 1000int ticket_count = TOTAL_TICKETS;
pthread_mutex_t lock;void* sell_tickets(void* arg) {while (1) {pthread_mutex_lock(&lock); // 加锁if (ticket_count <= 0) {pthread_mutex_unlock(&lock); // 解锁break;}// 模拟售票处理时间struct timespec sleep_time = {0, 1000000}; // 1毫秒nanosleep(&sleep_time, NULL);printf("线程%ld卖出第%d张票\n", (long)arg, ticket_count);ticket_count--;pthread_mutex_unlock(&lock); // 解锁}return NULL;
}int main() {pthread_t threads[NUM_THREADS];pthread_mutex_init(&lock, NULL);// 创建售票线程for (long i = 0; i < NUM_THREADS; i++) {pthread_create(&threads[i], NULL, sell_tickets, (void*)i);}// 等待所有线程完成for (int i = 0; i < NUM_THREADS; i++) {pthread_join(threads[i], NULL);}pthread_mutex_destroy(&lock);printf("所有票已售罄\n");return 0;
}

4. 线程安全

线程安全是指在多线程环境中,多个线程并发执行时,不会产生数据竞争、死锁等问题,保证程序的正确性

4.1 避免数据竞争

数据竞争发生在多个线程同时访问共享数据时,其中至少有一个线程进行写操作。如果没有同步机制,可能导致数据的不一致。常见的解决方法是使用 互斥锁原子操作

http://www.dtcms.com/a/294282.html

相关文章:

  • Linux中常见的中英文单词对照表
  • 低代码中的统计模型是什么?有什么作用?
  • 第一二章知识点
  • 交换机的六种常见连接方式配置(基于华为eNSP)
  • 洛谷刷题7.23
  • 电子公章怎么弄到合同上?2025最新指南
  • Android NDK与JNI深度解析
  • 为什么本地ip记录成0.0.0.1
  • 观影《长安的荔枝》有感:SwiftUI 中像“荔枝转运”的关键技术及启示
  • SpringMVC快速入门之请求与响应
  • TODAY()-WEEKDAY(TODAY(),2)+1
  • BEVDet-4D 代码详细解析
  • 《汇编语言:基于X86处理器》第9章 复习题和练习
  • Linux内存映射原理
  • 基于MCP架构的LLM-Agent融合—构建AI Agent的技术体系与落地实践
  • day060-zabbix监控各种客户端
  • 力扣MySQL(1)
  • python 字符串常用处理函数
  • Zookeeper学习专栏(七):集群监控与管理
  • 解决代码生成过程虚拟总线信号无法直接传递给自定义总线信号问题的方法
  • Python curl_cffi库详解:从入门到精通
  • Redis能完全保证数据不丢失吗?
  • 基于OpenOCD 的 STM32CubeIDE 开发烧录调试环境搭建 DAPLINK/STLINK
  • 《计算机网络》实验报告六 电子邮件
  • 【轨物方案】分布式光伏电站运维升级智能化系列:老电站的数智化重生
  • Zabbix 企业级分布式监控
  • Axios 响应拦截器
  • dfaews
  • vue3笔记(2)自用
  • 设备虚拟化技术