linux 内核同步互斥技术之信号量

信号量

信号量允许多个进程同时进入临界区,大多数情况下只允许一个进程进入临界区,把信号量的计数值设置为 1,即二值信号量,这种信号量称为互斥信号量。可允许多个锁持有者。
和自旋锁相比,信号量适合保护比较长的临界区,因为竞争信号量时进程可能睡眠和再次唤醒,代价很高。中断服务函数不能进行睡眠,因此信号量不能用于中断当中
信号量的使用流程:
定义一个信号量
    ↓
初始化信号量
    ↓
获得信号量(减操作)
    ↓
释放信号量(加操作)

内核使用的信号量定义如下:
include/linux/semaphore.h
struct semaphore {
    raw_spinlock_t      lock;
    unsigned int        count;
    struct list_head    wait_list;
};
成员 lock 是自旋锁,用来保护信号量的其他成员。
成员 count 是计数值,表示还可以允许多少次进入临界区。
成员 wait_list 是等待进入临界区的进程链表。
struct semaphore_waiter {
    struct task_struct *task;
    bool up;
    struct list_head list;
};

初始化静态信号量的方法如下。
(1)    __SEMAPHORE_INITIALIZER(name, n):指定名称和计数值,允许同时n 次进入临界区。
(2)    DEFINE_SEMAPHORE(name):初始化一个互斥信号量。
在运行时动态初始化信号量的方法如下:
static inline void sema_init(struct semaphore *sem, int val);
参数 val 指定允许同时进入临界区的数量。
获取信号量的函数如下。
(1) void down(struct semaphore *sem);
获取信号量,如果计数值是 0,进程深度睡眠。
(2) int down_interruptible(struct semaphore *sem);
获取信号量,如果计数值是 0,进程轻度睡眠(可以被系统消息打断,该函数的调用允许中断)。如果返回0,表示获得信号量正常返回,如果被信号打断,返回-EINTR。
(3) int down_killable(struct semaphore *sem);
获取信号量,如果计数值是 0,进程中度睡眠(可以因为受到致命信号而被唤醒)。
(4) int down_trylock(struct semaphore *sem);
获取信号量,如果计数值是 0,进程不等待不会导致调用者睡眠。
(5) int down_timeout(struct semaphore *sem, long jiffies);
获取信号量,指定等待的时间。
释放信号量的函数如下:
void up(struct semaphore *sem);


使用示例

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h> 
#include <linux/semaphore.h> 
#include <linux/delay.h>

int num[2][5]= { {
        0,2,4,6,8
    }
    , {
        1,3,5,7,9
    }
}
;
struct semaphore sem_first;
struct semaphore sem_second;
struct task_struct * task1;
struct task_struct * task2;

int thread_print_first(void *p) {
    int i;
    int *num=(int *)p;
    if(kthread_should_stop()){
        return 0;
    }
    printk(KERN_ALERT"Hello World:first\n");
    for (i=0;i<5;i++) {
        down(&sem_first);
        printk(KERN_ALERT"Hello World:%d\n",num[i]);
        up(&sem_second);
    }
    do {
        msleep(1000);
    }
    while(!kthread_should_stop());
    return 0;
}

int thread_print_second(void *p) {
    int i;
    int *num=(int *)p;
    if(kthread_should_stop()){
        return 0;
    }
    printk(KERN_ALERT"Hello World:second\n");
    for (i=0;i<5;i++) {
        down(&sem_second);
        printk(KERN_ALERT"Hello World:%d\n",num[i]);
        up(&sem_first);
    }
    do {
        msleep(1000);
    }
    while(!kthread_should_stop());
    return 0;
}

static int hello_init(void) {
    printk(KERN_ALERT"Hello World enter\n");
    sema_init(&sem_first,1);
    sema_init(&sem_second,0);
    task1 = kthread_create(thread_print_first,num[0],"first");
    if(IS_ERR(task1)) {
        printk(KERN_ALERT"kthread_create error!\n");
        return -1;
    }
    task2 = kthread_create(thread_print_second,num[1],"second");
    if(IS_ERR(task2)) {
        printk(KERN_ALERT"kthread_create error!\n");
        kthread_stop(task1);
        return -1;
    }
    wake_up_process(task1);
    wake_up_process(task2);
    return 0;
}

static void hello_exit(void) {
    int ret;
    if (!IS_ERR(task1)) {
        ret = kthread_stop(task1);
        printk("<<<<<<<<task1 exit, ret = %d\n", ret);
    }
    if (!IS_ERR(task2)) {
        ret = kthread_stop(task2);
        printk("<<<<<<<<task2 exit, ret = %d\n", ret);
    }
    printk(KERN_ALERT"hello world exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/199796.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java-宋红康-(P133-P134)-多线程创建方式(Thread and Runnable)

b站视频 133-多线程-线程创建方式1&#xff1a;继承Thread类_哔哩哔哩_bilibili 目录 3.1 继承Thread 3.1.1 继承Thread类方式 3.1.2 线程的执行流程 3.1.3 线程内存图 3.1.4 run()方法和start()方法 3.1.5 线程名字的设置和获取 3.1.6 获取运行main方法线程的名字 3.…

Linux进程间通信之共享内存

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;Linux &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客主要内容讲解共享内存原理和相关接口的介绍&#xff0c;以及一个…

更换cmd下默认选择Python解释器

问题 我的电脑里有多个Python解释器&#xff0c;一个是自己下载的python37&#xff0c;版本是3.7.0&#xff0c;一个是anaconda的base环境&#xff0c;版本是3.7.4&#xff0c;还有虚拟环境里的python解释器。 最近发现&#xff0c;在cmd下输入python&#xff0c;使用的是anac…

肺是人体的第一道防线,流感频发季节,最有效的养肺方法你得知道!

肺脏是人体的第一道防线&#xff0c;牵动着整个呼吸道的健康&#xff0c;一旦肺脏受损&#xff0c;易引发咳嗽、气喘甚至肺炎。在流感、呼吸道疾病高发的冬季&#xff0c;如何呵护肺脏&#xff0c;保持身体健康&#xff1f; 全民养肺&#xff0c;刻不容缓 养肺不仅仅是中老年朋…

深入浅出之中央空调体系架构及楼宇自控系统

一、关于建筑节能 1、建筑能耗 在中国&#xff0c;建筑能耗占社会总能耗45.5%。来源&#xff1a;《中国建筑能耗研究报告&#xff08;2022&#xff09;》 2、空调、采暖、照明占比最高 建筑节能是指在保证、提高建筑舒适性和生活质量的条件下&#xff0c;在建筑物使用的全过…

12.5 作业

1&#xff0c; 以下是一个简单的比喻&#xff0c;将多态概念与生活中的实际情况相联系&#xff1a; 比喻&#xff1a;动物园的讲解员和动物表演 想象一下你去了一家动物园&#xff0c;看到了许多不同种类的动物&#xff0c;如狮子、大象、猴子等。现在&#xff0c;动物园里有…

【Qt开发流程】之对象模型2:属性系统

描述 Qt提供了一个复杂的属性系统&#xff0c;类似于一些编译器供应商提供的属性系统。然而&#xff0c;作为一个独立于编译器和平台的库&#xff0c;Qt不依赖于非标准的编译器特性&#xff0c;如__property或[property]。 Qt解决方案适用于Qt支持的所有平台上的任何标准c编译…

力扣第374场周赛题解

这一场周赛的题目是比较难的一次&#xff0c;写了1个多小时就写了两个题目。 首先第一题&#xff1a; 纯水题&#xff0c;遍历然后进行一下判断就可以解决了。这边就不放代码了。 第二题&#xff1a; 这个题目&#xff0c;我觉得难度非常大&#xff0c;其实代码量也不大都是很…

IOday3作业

1> 使用文件IO完成对图像的读写操作 #include<myhead.h>int main(int argc, const char *argv[]) {//只读打开图片int fd-1;if((fd open("./R-C.bmp",O_RDWR))-1){perror("open");return -1;}//向后便宜两个字节找到大小的起始地址lseek(fd,2,S…

【数据结构】二叉树的实现

目录 1. 前言2. 二叉树的实现2.1 创建一棵树2.2 前序遍历2.2.1 分析2.2.2 代码实现2.2.3 递归展开图 2.3 中序遍历2.3.1 分析2.3.2 代码实现2.3.3 递归展开图 2.4 后序遍历2.4.1 分析2.4.2 代码实现2.4.3 递归展开图 2.5 求节点个数2.5.1 分析2.5.2 代码实现 2.6 求叶子节点个数…

Linux 调试器 --- g d b 使用

目录 一&#xff1a;gdb简介 二&#xff1a;示例代码 三&#xff1a;使用 1.启动gdb 2.各种指令 <1>: 查看源代码 <2>:设置断点 <3>:查看断点信息 <4>:删除断点 <5>: run <6>:逐过程调试 <7>:逐语句调试 <8>:查…

TrustZone​之在安全状态之间切换

如果处理器处于NS.EL1,而软件想要转移到S.EL1,应该如何实现呢? 要改变安全状态,无论是向上还是向下,执行都必须经过EL3,如下图所示: 前面的图表显示了在不同安全状态之间移动涉及的步骤的示例序列。逐步进行解释: 进入较高的异常级别需要一个异常。通常,此异常…

相关基础知识

本文引注&#xff1a; https://zhuanlan.zhihu.com/p/447221519 1.方差 2.自协方差矩阵 3.自相关矩阵 4.互协方差矩阵 5.互相关矩阵 6.相关系数 7.自相关函数、自协方差函数与功率谱密度 8.互相关函数、互协方差函数与互功率谱密度

时间选择器

<el-form-item label"时间范围"><!-- <el-date-picker size"small"v-model"createTime"type"daterange"range-separator"至"start-placeholder"请输入起始创建时间"end-placeholder"请输入终止创…

无线网优AP、SW发现控制器

目录 无线网优解决的问题 1、信号覆盖不足的原因 2、信道繁忙 3、非802.11干扰 4、协商速率低 5、漫游效果差 6、有线带宽阻塞 无线网优方法 交换机发现与激活 一&#xff0c;交换机发现控制器方式 1、二层广播 2、DHCP option43方式 3、DNS域名解析方式 4、trou…

基于springboot + vue大学生竞赛管理系统

qq&#xff08;2829419543&#xff09;获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;springboot 前端&#xff1a;采用vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xf…

【AIGC】AI作图最全提示词prompt集合(收藏级)

目录 一、正向和负向提示词 二、作图参数 你好&#xff0c;我是giszz. AI做图真是太爽了&#xff0c;解放生产力&#xff0c;发展生产力。 但是&#xff0c;你是不是也总疑惑&#xff0c;为什么别人的图&#xff0c;表现力那么丰富呢&#xff0c;而且指哪打哪&#xff0c;要…

DFT(离散傅里叶变换)的通俗理解

本文包含了博主对离散傅里叶变换&#xff0c;负频率&#xff0c;实信号与复信号频谱的理解&#xff0c;如有不妥&#xff0c;欢迎各位批评指正与讨论。 文章目录 DFT的理解信号的频谱实信号的频谱复信号的频谱 DFT的理解 傅里叶变换是一种将信号从时域转换到频域的数学工具。…

通信标准化协会,信通院及量子信息网络产业联盟调研玻色量子,共绘实用化量子未来!

8月14日&#xff0c;中国通信标准化协会&#xff0c;信通院标准所及量子信息网络产业联盟等单位领导走访调研北京玻色量子科技有限公司&#xff08;以下简称“玻色量子”&#xff09;&#xff0c;参观了玻色量子公司及自建的十万颗粒洁净度的光量子信息技术实验室&#x1f517;…

STM32下载程序的五种方法

刚开始学习 STM32 的时候&#xff0c;很多小伙伴满怀热情买好了各种设备&#xff0c;但很快就遇到了第一个拦路虎——如何将写好的代码烧进去这个黑乎乎的芯片&#xff5e; STM32 的烧录方式多样且灵活&#xff0c;可以根据实际需求选择适合的方式来将程序烧录到芯片中。本文将…