主要介绍一下Linux下的互斥与阻塞方面的知识:

1. 原子操作

原子操作指的是在执行过程中不会被别的代码路径所中断的操作。

常用原子操作函数举例:

atomic_t v = ATOMIC_INIT(0);     //定义原子变量v并初始化为0

atomic_read(atomic_t *v);        //返回原子变量的值

void atomic_inc(atomic_t *v);    //原子变量增加1

void atomic_dec(atomic_t *v);    //原子变量减少1

int atomic_dec_and_test(atomic_t *v); //自减操作后测试其是否为0,为0则返回true,否则返回false。

2. 信号量

信号量(semaphore)是用于保护临界区的一种常用方法,只有得到信号量的进程才能执行临界区代码。

当获取不到信号量时,进程进入休眠等待状态。

定义信号量

struct semaphore sem;

初始化信号量

void sema_init (struct semaphore *sem, int val);

void init_MUTEX(struct semaphore *sem);//初始化为0

static DECLARE_MUTEX(button_lock);     //定义互斥锁

获得信号量

void down(struct semaphore * sem);

int down_interruptible(struct semaphore * sem);

int down_trylock(struct semaphore * sem);

释放信号量

void up(struct semaphore * sem);

3. 阻塞

阻塞操作

是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。

被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。

非阻塞操作

进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。

fd = open("...", O_RDWR | O_NONBLOCK);

示例代码:

1.应用程序:

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <poll.h>

#include <signal.h>

#include <sys/types.h>

#include <unistd.h>

#include <fcntl.h>

/* sixthdrvtest

*/

int fd;

void my_signal_fun(int signum)

{

unsigned char key_val;

read(fd, &key_val, 1);

printf("key_val: 0x%x\n", key_val);

}

int main(int argc, char **argv)

{

unsigned char key_val;

int ret;

int Oflags;

//signal(SIGIO, my_signal_fun);

fd = open("/dev/buttons", O_RDWR | O_NONBLOCK);

if (fd < 0)

{

printf("can't open!\n");

return -1;

}

//fcntl(fd, F_SETOWN, getpid());

//Oflags = fcntl(fd, F_GETFL);

//fcntl(fd, F_SETFL, Oflags | FASYNC);

while (1)

{

ret = read(fd, &key_val, 1);

printf("key_val: 0x%x, ret = %d\n", key_val, ret);

sleep(5);

}

return 0;

}

2.驱动程序:

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/delay.h>

#include <linux/irq.h>

#include <asm/uaccess.h>

#include <asm/irq.h>

#include <asm/io.h>

#include <asm/arch/regs-gpio.h>

#include <asm/hardware.h>

#include <linux/poll.h>

static struct class *sixthdrv_class;

static struct class_device *sixthdrv_class_dev;

volatile unsigned long *gpfcon;

volatile unsigned long *gpfdat;

volatile unsigned long *gpgcon;

volatile unsigned long *gpgdat;

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

/* 中断事件标志, 中断服务程序将它置1,sixth_drv_read将它清0 */

static volatile int ev_press = 0;

static struct fasync_struct *button_async;

struct pin_desc{

unsigned int pin;

unsigned int key_val;

};

/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */

/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */

static unsigned char key_val;

struct pin_desc pins_desc[4] = {

{S3C2410_GPF0, 0x01},

{S3C2410_GPF2, 0x02},

{S3C2410_GPG3, 0x03},

{S3C2410_GPG11, 0x04},

};

//static atomic_t canopen = ATOMIC_INIT(1);     //定义原子变量并初始化为1

static DECLARE_MUTEX(button_lock);     //定义互斥锁

/*

* 确定按键值

*/

static irqreturn_t buttons_irq(int irq, void *dev_id)

{

struct pin_desc * pindesc = (struct pin_desc *)dev_id;

unsigned int pinval;

pinval = s3c2410_gpio_getpin(pindesc->pin);

if (pinval)

{

/* 松开 */

key_val = 0x80 | pindesc->key_val;

}

else

{

/* 按下 */

key_val = pindesc->key_val;

}

ev_press = 1;                  /* 表示中断发生了 */

wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */

kill_fasync (&button_async, SIGIO, POLL_IN);

return IRQ_RETVAL(IRQ_HANDLED);

}

static int sixth_drv_open(struct inode *inode, struct file *file)

{

#if 0

if (!atomic_dec_and_test(&canopen))

{

atomic_inc(&canopen);

return -EBUSY;

}

#endif

if (file->f_flags & O_NONBLOCK)

{

if (down_trylock(&button_lock))

return -EBUSY;

}

else

{

/* 获取信号量 */

down(&button_lock);

}

/* 配置GPF0,2为输入引脚 */

/* 配置GPG3,11为输入引脚 */

request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);

request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);

request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);

request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);

return 0;

}

ssize_t sixth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)

{

if (size != 1)

return -EINVAL;

if (file->f_flags & O_NONBLOCK)

{

if (!ev_press)

return -EAGAIN;

}

else

{

/* 如果没有按键动作, 休眠 */

wait_event_interruptible(button_waitq, ev_press);

}

/* 如果有按键动作, 返回键值 */

copy_to_user(buf, &key_val, 1);

ev_press = 0;

return 1;

}

int sixth_drv_close(struct inode *inode, struct file *file)

{

//atomic_inc(&canopen);

free_irq(IRQ_EINT0, &pins_desc[0]);

free_irq(IRQ_EINT2, &pins_desc[1]);

free_irq(IRQ_EINT11, &pins_desc[2]);

free_irq(IRQ_EINT19, &pins_desc[3]);

up(&button_lock);

return 0;

}

static unsigned sixth_drv_poll(struct file *file, poll_table *wait)

{

unsigned int mask = 0;

poll_wait(file, &button_waitq, wait); // 不会立即休眠

if (ev_press)

mask |= POLLIN | POLLRDNORM;

return mask;

}

static int sixth_drv_fasync (int fd, struct file *filp, int on)

{

printk("driver: sixth_drv_fasync\n");

return fasync_helper (fd, filp, on, &button_async);

}

static struct file_operations sencod_drv_fops = {

.owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

.open    =  sixth_drv_open,

.read  = sixth_drv_read,

.release =  sixth_drv_close,

.poll    =  sixth_drv_poll,

.fasync  =  sixth_drv_fasync,

};

int major;

static int sixth_drv_init(void)

{

major = register_chrdev(0, "sixth_drv", &sencod_drv_fops);

sixthdrv_class = class_create(THIS_MODULE, "sixth_drv");

sixthdrv_class_dev = class_device_create(sixthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */

gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);

gpfdat = gpfcon + 1;

gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);

gpgdat = gpgcon + 1;

return 0;

}

static void sixth_drv_exit(void)

{

unregister_chrdev(major, "sixth_drv");

class_device_unregister(sixthdrv_class_dev);

class_destroy(sixthdrv_class);

iounmap(gpfcon);

iounmap(gpgcon);

return 0;

}

module_init(sixth_drv_init);

module_exit(sixth_drv_exit);

MODULE_LICENSE("GPL");

最后附笔者学习笔记:

Linux之同步互斥阻塞20160703的更多相关文章

  1. 入门级的按键驱动——按键驱动笔记之poll机制-异步通知-同步互斥阻塞-定时器防抖

    文章对应视频的第12课,第5.6.7.8节. 在这之前还有查询方式的驱动编写,中断方式的驱动编写,这篇文章中暂时没有这些类容.但这篇文章是以这些为基础写的,前面的内容有空补上. 按键驱动——按下按键, ...

  2. Linux中同步互斥机制研究之原子操作

    操作系统中,对共享资源的访问需要有同步互斥机制来保证其逻辑的正确性,而这一切的基础便是原子操作. | 原子操作(Atomic Operations):    原子操作从定义上理解,应当是类似原子的,不 ...

  3. Linux IO 同步/异步 阻塞/非阻塞

    同步IO:导致请求进程阻塞,直到IO操作完成: 是内核通知我们何时进行启动IO操作,而实际的IO操作需要当前进程本身阻塞完成: 包括:阻塞式IO模型,非阻塞式IO模型,IO复用模型,信号驱动式IO模型 ...

  4. Linux多线程(三)(同步互斥)

    1. 线程的同步与互斥 1.1. 线程的互斥 在Posix Thread中定义了一套专门用于线程互斥的mutex函数.mutex是一种简单的加锁的方法来控制对共享资源的存取,这个互斥锁只有两种状态(上 ...

  5. 【Linux】Mutex互斥量线程同步的例子

    0.互斥量  Windows下的互斥量 是个内核对象,每次WaitForSingleObject和ReleaseMutex时都会检查当前线程ID和占有互斥量的线程ID是否一致. 当多次Wait**时就 ...

  6. Linux同步互斥(Peterson算法,生产者消费者模型)

    同步 两个或两个以上随时间变化的量在变化过程中保持一定的相对关系. 互斥 对一组并发进程,一次只有一个进程能够访问一个给定的资源或执行一个给定的功能. 互斥技术可以用于解决诸如资源争用之类的冲突,还可 ...

  7. Linux中同步与异步、阻塞与非阻塞概念以及五种IO模型

    1.概念剖析 相信很多从事linux后台开发工作的都接触过同步&异步.阻塞&非阻塞这样的概念,也相信都曾经产生过误解,比如认为同步就是阻塞.异步就是非阻塞,下面我们先剖析下这几个概念分 ...

  8. Linux下同步模式、异步模式、阻塞调用、非阻塞调用总结

    转自:http://www.360doc.com/content/13/0117/12/5073814_260691714.shtml 同步和异步:与消息的通知机制有关. 本质区别 现实例子 同步模式 ...

  9. Linux多线程同步方式

    当多个线程共享相同的内存时,需要确保每个线程看到一致的数据视图,当多个线程同时去修改这片内存时,就可能出现偏差,得到与预期不符合的值.为啥需要同步,一件事情逻辑上一定是有序的,即使在并发环境下:而操作 ...

随机推荐

  1. JVM常见配置

    堆设置 -Xms:初始堆大小 -Xmx:最大堆大小 -XX:NewSize=n:设置年轻代大小 -XX:NewRatio=n:设置年轻代和年老代的比值.如:为3,表示年轻代与年老代比值为1:3,年轻代 ...

  2. asp.net core2.1项目应用Ant Design(一)

    无意中发现了Ant Design这个组件库后,深深被他丰富的组件吸引了,大家感兴趣的可以去官网感受下,组件的应用和效果真是的太强大了,对于我们这些小公司,无自主研发前端团队的来说,无疑特别方便:htt ...

  3. Python中assert的作用?

    1. assert 的作用是什么? assert这个关键字我们称之为“断言”,当这个关键字后边的条件为假的时候,程序自动崩溃并抛出AssertionError的异常. 什么情况下我们会需要这样的代码呢 ...

  4. Java开发工程师(Web方向) - 01.Java Web开发入门 - 第5章.Git

    第5章--Git 版本控制简介 VCS (version control system) 版本控制系统:记录若干文件的修订记录的系统,帮助查阅/回到某个历史版本 LVCS本地 CVCS集中式(Cent ...

  5. 【WXS数据类型】RegExp

    生成 regexp 对象需要使用 getRegExp函数,注意与JS的使用方法不同( new RegExp(pattern,modifiers);) 原型:getRegExp(pattern, mod ...

  6. AttributeError: 'TimeLimit' object has no attribute 'monitor'

    原报错代码部分: env.monitor.start(monitor_path, resume=True, video_callable=lambda count: count % record_vi ...

  7. leetcode个人题解——#8 string to integer

    第八题 class Solution { public: int myAtoi(string str) { ; ; ; while(str[i] == ' ')i++; if (str[i] == ' ...

  8. 在JS中 实现不用中间变量temp 实现两个变量值得交换

    1.使用加减法; var a=1; var b=2; a=a+b; b=a-b; a=a-b; 2.使用乘除法(乘除法更像是加减法向乘除运算的映射) var a=1; var b=2; a = a * ...

  9. Sail

    DescriptionThe polar bears are going fishing. They plan to sail from (sx,?sy) to (ex,?ey). However, ...

  10. Deeplearning——Logistics回归

    资料来源:1.博客:http://binweber.top/2017/09/12/deep_learning_1/#more——转载,修改更新 2.文章:https://www.qcloud.com/ ...