主要介绍一下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. JavaScript基本概念(1)-声明提升

    声明提升: function > var > other var提升的时候,只是声明提升,但是赋值还是会在原来的位置. Javascript Hoisting:In javascript, ...

  2. 41. Maximum Subarray

    Description Given an array of integers, find a contiguous subarray which has the largest sum. The su ...

  3. 爬虫1.6-selenium+HeadlessChrome

    目录 爬虫-selenium+HeadlessChrome 1. 浏览器处理步骤 2. headless-chrome初体验 3. 实战爬取淘宝镇.街道信息 爬虫-selenium+HeadlessC ...

  4. spark相关脚本解析

    spark-shell/spark-submit/pyspark等关系如下: #spark-submit 逻辑: ########################################### ...

  5. 基础数据类型-set

    Set是无序不重复元素的序列,基本功能是删除重复元素和测试成员关系, 创建一个集合可以用set()或者({}),但是创建一个空集合只能用set(): s1 = set() print("s1 ...

  6. POJ 3845 Fractal(计算几何の旋转缩放)

    Description Fractals are really cool mathematical objects. They have a lot of interesting properties ...

  7. Nodejs中关于模块的总结

    关于Nodejs中的模块 概念 Nodejs在ECMAScript的基础上扩展并封装了许多高级特性,如文件访问.网络访问等,使得Nodejs成为一个很好的Web开发平台.基于Nodejs这个平台将We ...

  8. 《梦断代码Dreaming In Code》阅读计划

    书籍是人类宝贵的精神财富,读书是人们重要的学习方式,是人生奋斗的航灯,是文化传承的通道,是人类进步的阶梯.学生作为学习人群的主体,必须把读书作为头等大事.学校就是一个学生在教师指导下自主读书的空间,而 ...

  9. 用URL传参带特殊字符,特殊字符丢失

    文章:URL中编码URL特殊字符 文章:用URL传参带特殊字符,特殊字符丢失(encode) 如果url中有特殊字符,需要对url进行编码,否则特殊字符丢失,导致最终接收到的值不对.

  10. 用 C# 实现文件信息统计(wc)命令行程序

    软件的需求分析 程序处理用户需求的模式为: wc.exe [parameter][filename] 在[parameter]中,用户通过输入参数与程序交互,需实现的功能如下: 1.基本功能 支持 - ...