写点什么

Linux 系统编程 -(pthread) 线程通信 (信号量)

作者:DS小龙哥
  • 2022 年 2 月 12 日
  • 本文字数:1682 字

    阅读完需:约 6 分钟

1. 信号量介绍

信号量的运用环境与互斥锁一样,但是信号量比互斥锁增加灵活,互斥锁只有两个状态(开锁和解锁),而信号量本质上是一个计数器,它内部有一个变量计数信号值,可以保护一个资源可以同时被 1 个或者 2 个或者 3 个线程同时使用,如果信号量的值只是设置 1(状态只有 0 和 1),那么和互斥锁就是一样的功能。


总结

  1. 信号量也主要是用来保护共享资源(信号量也属于临界资源),使得资源在一个时刻只有一个线程或者多个线程独享。

  2. 信号量是一种特殊的变量,访问具有原子性, 用于解决进程或线程间共享资源引发的同步问题。

  3. 信号量就是一个计数变量,内部本身就是一个变量。只不过这个变量具有原子性。

  4. 信号量经常用来保护临界区资源、实现资源同步。

  5. 如果信号量只有 2 个值,0 和 1,就称为二值信号量==互斥锁。


信号量和互斥锁(mutex)的区别: 互斥锁只允许一个线程进入临界区,而信号量允许多个线程同时进入临界区,要使用信号量同步,需要包含头文件semaphore.h

2. 信号量实现接口函数

2.1 始化信号量

#include <semaphore.h>int sem_init(sem_t *sem, int pshared, unsigned int value); //通常 pshared 为 0.表示线程间
复制代码


sem_init是创建信号量的 API,其中 value 为信号量的初值,pshared 表示是否为多进程共享而不仅仅是用于一个进程之间的多线程共享。


如果 pshared 的值为 0,那么信号量在进程的线程之间共享,并且应位于所有线程可见的某个地址(例如,全局变量)能够,或在堆上动态分配的变量),如果 pshared 不为零,那么信号量在进程之间共享,信号量的值就位于共享内存区域。

2.2 注销信号量

int sem_destroy(sem_t * sem);
复制代码


注销信号量时,必须保证被注销的信号量 sem 没有线程在等待该信号量,否则会返回-1,且置 errno 为 EBUSY。正常返回 0。

2.3 释放信号量

int sem_post(sem_t * sem); //相当于解锁
复制代码


释放信号量操作将信号量值原子地加 1,表示增加一个可访问的资源。只有信号量值大于 0,才能访问公共资源。主要用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞。

2.4 等待信号量

int sem_wait(sem_t * sem);     //相当于加锁int sem_trywait(sem_t * sem);   //不阻塞
复制代码


sem_wait()用于阻塞等待信号量(获取信号量),主要被用来阻塞当前线程直到信号量 sem 的值大于 0,得到信号量之后,信号量的值会减一。

2.5 获取当前的信号量值

int sem_getvalue(sem_t * sem, int * sval);
复制代码

读取 sem 中的信号量计数,存于*sval 中,并返回 0。

3. 案例代码: 信号量框架运用模型

#include <stdio.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <dirent.h>#include <stdlib.h>#include <pthread.h>#include <semaphore.h>
sem_t sem; //信号量结构
int data;/*线程工作函数*/void *thread_work_func(void *dev){ while(1) { sem_wait(&sem); //获取信号量. 当信号量的值大于0才能获取成功. -- printf("data=%d\n",data); sem_post(&sem); //释放信号量. ++ sleep(1); }}
/*线程工作函数*/void *thread_work_func2(void *dev){ while(1) { sem_wait(&sem); //获取信号量. 当信号量的值大于0才能获取成功. -- data++; sem_post(&sem); //释放信号量. ++ sleep(1); }}
int main(int argc,char **argv){ //初始化信号量 sem_init(&sem,0,1);
/*1. 创建子线程1*/ pthread_t thread_id; if(pthread_create(&thread_id,NULL,thread_work_func,NULL)!=0) { printf("子线程1创建失败.\n"); return -1; } /*2. 创建子线程2*/ pthread_t thread_id2; if(pthread_create(&thread_id2,NULL,thread_work_func2,NULL)!=0) { printf("子线程2创建失败.\n"); return -1; }
/*3. 等待线程的介绍*/ pthread_join(thread_id,NULL); pthread_join(thread_id2,NULL);
//销毁信号量 sem_destroy(&sem); return 0;}
复制代码


发布于: 2022 年 02 月 12 日阅读数: 4
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022.01.06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
Linux系统编程-(pthread)线程通信(信号量)