news 2026/4/17 20:31:51

线程并发编程,同步与互斥机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
线程并发编程,同步与互斥机制

线程

概念

线程是一个轻量级的进程,为了提高系统的性能引入线程。

线程和进程都参与统一的调度。

在同一个进程中可以创建多个线程,并且共享进程资源。

进程和线程区别(面试题)

相同点:都为操作系统提供了并发执行的能力

不同点:

资源和调度:进程是系统资源分配的最小单位,线程是资源调度的最小单位

地址空间方面:每个进程都有独立的地址空间;同一个进程中的多个线程共享进程地址空间

通信方面:线程通信相对简单,只需要通过全局变量就可以实现,但是需要考虑临界资源访问的问题; 进程通信比较复杂,需要借助进程间的通信机制(3-4g的内核空间)。

安全性方面:线程安全性差一些,当进程结束时会导致所有线程退出; 进程相对安全。

线程资源

共享的资源:可执行的指令、静态数据、进程中打开的文件描述符、信号处理函数、当前工作目录、用户ID、用户组ID

私有的资源:线程ID (TID)、PC(程序计数器)和相关寄存器、堆栈(局部变量, 返回地址)、错误号 (errno)、信号掩码和优先级、执行状态和属性

函数接口

创建线程:pthread_create

#include<pthread.h>intpthread_create(pthread_t*thread,constpthread_attr_t*attr,void*(*start_routine)(void*),void*arg);功能:创建线程参数:thread:线程标识attr:线程属性,NULL代表设置默认属性start_routine:函数名:代表线程函数(自己写)arg:用来给前面函数传参返回值:成功:0失败:错误码编译的时候需要加-lpthread 链接动态库

退出线程:pthread_exit

#include<pthread.h>voidpthread_exit(void*retval);功能:用于退出线程的执行参数:retval:线程退出时返回的值
#include <stdio.h>#include <pthread.h>#include <unistd.h>void *handler(void *arg){printf("in the thread\n");pthread_exit(NULL); // 让线程退出while(1);return NULL;}int main(int argc, char const *argv[]){pthread_t tid;if(pthread_create(&tid, NULL, handler, NULL) != 0){perror("create thread err");}// 主线程printf("in the main\n");while(1);return 0;}

回收线程资源

#include <pthread.h>int pthread_join(pthread_t thread, void **retval);功能:用于等待一个指定的线程结束,阻塞函数参数:thread:创建的线程对象,线程IDretval指针*value_ptr指向线程返回的参数,一般为NULL返回值:成功:0失败:errnoint pthread_detach(pthread_t thread);功能:让线程结束时自动回收线程资源,让线程和主线程分离,非阻塞函数参数:thread:线程ID非阻塞式的,例如主线程分离(detach)了线程T2,那么主线程不会阻塞在pthread_detach(),pthread_detach()会直接返回,线程T2终止后会被操作系统自动回收资源
#include <stdio.h>#include <pthread.h>#include <unistd.h>void *handler(void *arg){printf("in the thread\n");sleep(2);pthread_exit(NULL); // 让线程退出while(1);return NULL;}int main(int argc, char const *argv[]){pthread_t tid;if(pthread_create(&tid, NULL, handler, NULL) != 0){perror("create thread err");}// pthread_join(tid, NULL); // 阻塞等待指定线程退出回收资源pthread_detach(tid); // 非阻塞,让指定的线程为分离态,结束时自动回收资源// 主线程printf("in the main\n");while(1);return 0;}
练习:输入输出,quit结束

通过线程实现数据的交互,主线程循环从终端输入,线程函数将数据循环输出,当输入quit结束程序。

  1. 全局变量
  2. 加上标志位(flag),实现主线程输入一次修改标志位,从线程打印一次也修改标志位, int flag=0;
#include <stdio.h>#include <pthread.h>#include <unistd.h>#include <string.h>char buf[32] = {};int flag = 0;void *handler(void *arg){while (1){if (flag == 1){if (!strcmp(buf, "quit"))break;printf("%s\n", buf);flag = 0;}}return NULL;}int main(int argc, char const *argv[]){pthread_t tid;if (pthread_create(&tid, NULL, handler, NULL) != 0){perror("create thread err");}while (1){scanf("%s", buf);flag = 1;if (!strcmp(buf, "quit"))break;}pthread_join(tid, NULL);return 0;}

在应用层中有这两个概念:

同步:现在有两件事都是你应该去做的事情,那么这两件事是不是有先后的顺序

异步:我在做一件事情的同时还可以去做另一件事情

线程同步

概念:

多个线程(任务)按照约定的顺序相互配合完成一件事情

同步机制

通过信号量实现线程同步

信号量:通过信号量实现同步操作; 由信号量来决定线程继续运行还是阻塞等待。

信号量:代表一类资源,其值可以表示系统中该资源的数量。

信号量的值>0: 表示有资源可以用,可以申请到资源。

信号量的值<=0: 表示没有资源可以用,无法申请到资源,阻塞。

信号量:还是受保护的变量,只能通过三种操作来访问:初始化,P操作(申请资源),V操作(释放资源)

sem_init:信号量初始化

sem_wait:申请资源,P操作,如果没有资源可用则阻塞,否则就申请到资源 -1

sem_post:释放资源,V操作,非阻塞,+1

int sem_init(sem_t *sem, int pshared, unsigned int value)功能:初始化信号量参数:sem:初始化的信号量对象pshared:信号量共享的范围(0: 线程间使用 非0:1进程间使用)value:信号量初值返回值:成功 0失败 -1int sem_wait(sem_t *sem)功能:申请资源 P操作参数:sem:信号量对象返回值:成功 0失败 -1注:此函数执行过程,当信号量的值大于0时,表示有资源可以用,则继续执行,同时对信号量减1;当信号量的值等于0时,表示没有资源可以使用,函数阻塞int sem_post(sem_t *sem)功能:释放资源 V操作参数:sem:信号量对象返回值:成功 0失败 -1注:释放一次信号量的值加1,函数不阻塞
#include <stdio.h>#include <semaphore.h>int main(int argc, char const *argv[]){sem_t sem;if(sem_init(&sem, 0, 1) < 0){perror("sem init err");return -1;}// 申请资源 -> P操作sem_wait(&sem);printf("hello\n");// 释放资源sem_post(&sem);sem_wait(&sem); // 没有释放资源,会进入阻塞状态printf("world\n");return 0;}

线程互斥

互斥概念

多个线程访问临界资源时,同一时间只能一个线程访问

临界资源:多个线程共同访问的数据,且一次仅允许一个线程所使用的资源

通过互斥锁可以实现互斥机制,主要用来保护临界资源,每个临界资源都由一个互斥锁来保护,线程必须先获得互斥锁才能访问临界资源,访问完资源后释放该锁。如果无法获得锁,线程会阻塞直到获得锁为止。

互斥锁的操作方式:初始化

申请锁(上锁) :阻塞

当申请不到锁时(表示:锁被其它线程占用),是阻塞的

释放锁(解锁) :非阻塞

注意:上锁和解锁需要成对存在

函数接口

int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)功能:初始化互斥锁参数:mutex:互斥锁attr: 互斥锁属性 // NULL表示缺省属性返回值:成功 0失败 -1int pthread_mutex_lock(pthread_mutex_t *mutex)功能:申请互斥锁参数:mutex:互斥锁返回值:成功 0失败 -1注:和pthread_mutex_trylock区别:pthread_mutex_lock是阻塞的;pthread_mutex_trylock不阻塞,如果申请不到锁会立刻返回int pthread_mutex_unlock(pthread_mutex_t *mutex)功能:释放互斥锁参数:mutex:互斥锁返回值:成功 0失败 -1int pthread_mutex_destroy(pthread_mutex_t *mutex)功能:销毁互斥锁参数:mutex:互斥锁

补充:死锁

是指两个或两个以上的进程或线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。

死锁产生的四个必要条件

1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用

2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。

3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。

  1. 循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。

注意:当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 13:16:18

从“写代码”到“定义问题”——AI 时代程序员的生存宣言

本文原创公开首发于 CSDN 如需转载&#xff0c;请在文首注明出处与作者&#xff1a;yu779 从“写代码”到“定义问题”——AI 时代程序员的生存宣言 > “AI 一天写的代码&#xff0c;比我一周都多&#xff0c;那我还有存在的意义吗&#xff1f;” > 带着这个灵魂拷问&am…

作者头像 李华
网站建设 2026/4/16 0:38:02

iPhone运行Android完整指南:Project Sandcastle终极教程

iPhone运行Android完整指南&#xff1a;Project Sandcastle终极教程 【免费下载链接】projectsandcastle Supporting tools for Android/Linux on the iPhone 项目地址: https://gitcode.com/gh_mirrors/pr/projectsandcastle 在iPhone上运行Android系统&#xff0c;这听…

作者头像 李华
网站建设 2026/4/16 14:04:18

微信遥控Mac:WeChatPlugin远程控制终极指南

微信遥控Mac&#xff1a;WeChatPlugin远程控制终极指南 【免费下载链接】WeChatPlugin-MacOS 微信小助手 项目地址: https://gitcode.com/gh_mirrors/we/WeChatPlugin-MacOS 你是否曾经想过&#xff0c;躺在沙发上就能控制远在书房里的Mac电脑&#xff1f;或者在外出时突…

作者头像 李华
网站建设 2026/4/16 13:28:42

【Anthropic分享博客】Anthropic 内部的 Agentic Workflow 工程实践

摘要 随着 AI 辅助编程从单纯的 “Chat” 向 “Agentic”(代理式)演进, Claude Code 一直都是代表一种全新的工程交互范式。本文基于 Anthropic 最新分享看Claude Code的落地案例,尝试解析 Claude Code 的技术架构逻辑、上下文管理策略(Context Management)、以及基于 M…

作者头像 李华
网站建设 2026/4/16 12:34:14

ControlNet OpenPose SDXL:AI绘图的姿势控制终极指南

ControlNet OpenPose SDXL&#xff1a;AI绘图的姿势控制终极指南 【免费下载链接】controlnet-openpose-sdxl-1.0 项目地址: https://ai.gitcode.com/hf_mirrors/thibaud/controlnet-openpose-sdxl-1.0 在AI绘图领域&#xff0c;如何精确控制生成图像中人物的姿势一直是…

作者头像 李华
网站建设 2026/4/16 14:12:24

day36官方文档的阅读@浙大疏锦行

day36官方文档的阅读浙大疏锦行 准备工作 import pandas as pd from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier import pdpbox from pdpbox import pdp, info_plots# 打…

作者头像 李华