news 2026/10/16 4:12:45

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

作者头像

张小明

前端开发工程师

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/10/16 2:29:23

V助手舆情分析智能体:重塑舆情分析,从“人找信息”到“信息为人”

V助手舆情分析智能体&#xff1a;重塑舆情分析&#xff0c;从“人找信息”到“信息为人”在信息爆炸的时代&#xff0c;舆情分析工作常常面临数据繁杂、流程冗长、响应迟缓等挑战。传统方式不仅耗时耗力&#xff0c;更易错失关键信息与应对先机。如今&#xff0c;随着蜜度V助手…

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

连接2026:十款远程控制软件真实力横评与选择指南

目录引&#x1f4c8; 选择前必读&#xff1a;明确你的核心需求&#x1f3c6; 综合王者&#xff1a;ToDesk&#xff08;评分 9.6/10&#xff09;&#x1f3af; 细分领域佼佼者&#x1f3ae; 为游戏而生&#xff1a;网易UU远程&#xff08;评分 8.4/10&#xff09;&#x1f3ac; …

作者头像 李华
网站建设 2026/10/16 3:05:14

计算机毕业设计springboot基于Spark++Vue.js的学生管理系统 Spark+Vue 高校学生综合信息管理平台 基于 SpringBoot+Spark+Vue 的全链路学生事务中心

计算机毕业设计springboot基于SparkVue.js的学生管理系统i2kn7p36 &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。在“数据即资产”的校园时代&#xff0c;传统 Excel 与人工流转…

作者头像 李华
网站建设 2026/10/16 17:56:26

为什么 C盘空间会莫名其妙减少(即使没装新软件)?

为什么 C盘空间会莫名其妙减少&#xff08;即使没装新软件&#xff09;&#xff1f;你有没有注意到c盘空间在减少&#xff0c;即使你没有安装新程序, 这个常见问题可能让人担心, 但通常有明确原因, windows和其他软件会定期创建临时文件、系统备份和更新, 占用磁盘空间而不会每…

作者头像 李华
网站建设 2026/10/16 0:31:41

17、深入理解 Linux 文件系统机制与结构

深入理解 Linux 文件系统机制与结构 1. 理解长格式文件列表 在 Linux 中,使用 ls -la 命令可以查看详细的文件列表信息,示例输出如下: drwx------ 2 dee dee 4096 Jul 29 07:48 . drwxr-xr-x 5 root root 4096 Jul 27 11:57 .. -rw-r--r-- 1 dee dee 24 Jul 27 …

作者头像 李华