原文地址:
http://www.cnblogs.com/hebaichuanyeah/
1.关于并发控制
Linux 中多个进程对共享资源的并发访问,并发访问会导致竞态。
在单 CPU范围内避免竞态的一种方法是在进入临界区之前屏蔽系统的中断。CPU一般都具备屏蔽中断和打开中断的功能,中断屏蔽将使得中断与进程之间的并发不再发生,由于Linux 内核的进程调度等操作都依赖中断来实现,内核抢占进程之间的并发也就得以避免了。
local_irq_disable() //屏蔽中断
...
critical section //临界区
...
local_irq_enable() //开中断
原子操作
原子操作指的是在执行过程中不会被别的代码路径所中断的操作。
原子操作驱动
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <asm/uaccess.h> /* copy_to_user,copy_from_user */ #include <linux/miscdevice.h> #include <linux/pci.h> #include <mach/map.h> #include <mach/regs-gpio.h> #include <mach/gpio-bank-m.h> #include <plat/gpio-cfg.h> #define LED_MAJOR 240 //原子变量 atomic_t atomic_led = ATOMIC_INIT(0); int led_open (struct inode *inode,struct file *filp) { unsigned tmp; //减1兼测试 if (!atomic_dec_and_test(&atomic_led)) { //加1 atomic_inc(&atomic_led); return -1; } tmp = readl(S3C64XX_GPMDAT); tmp &= 0xffff0000; tmp |= 0x00001111; writel(tmp, S3C64XX_GPMCON); writel(0xffffffff, S3C64XX_GPMDAT); printk("<0>open led "); return 0; } ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos) { return count; } ssize_t led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos) { char wbuf[1]; unsigned tmp; copy_from_user(wbuf,buf,count); tmp = readl(S3C64XX_GPMDAT); tmp &= 0xfffffff0; tmp |= wbuf[0]; writel(tmp, S3C64XX_GPMDAT); return count; } int led_release (struct inode *inode, struct file *filp) { atomic_inc(&atomic_led); return 0; } struct file_operations led_fops ={ .owner = THIS_MODULE, .open = led_open, .read = led_read, .write = led_write, .release = led_release, }; int __init led_init (void) { int rc; printk ("<0>led init "); rc = register_chrdev(LED_MAJOR,"led",&led_fops); if (rc <0) { printk ("<0>register %s char dev error ","led"); return -1; } //atomic_t atomic_led = ATOMIC_INIT(0); //原子变量置1 atomic_set(&atomic_led, 1); printk ("<0>success "); return 0; } void __exit led_exit (void) { unregister_chrdev(LED_MAJOR,"led"); printk ("<0>module exit "); return ; } module_init(led_init); module_exit(led_exit);
测试程序
#include <fcntl.h> #include "stdio.h" #include "pthread.h" #include "stdlib.h" void thread_one(void) { int fd,count; char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff}; while((fd = open("/dev/my_led",O_RDWR))<0) { printf ("pthread_one:Open /dev/my_led file error "); //pthread_exit(0); sleep(1); } for(count=0;count<3;count++) { write(fd,&buf[0],1); sleep(1); write(fd,&buf[5],1); sleep(1); } close (fd); } void thread_two(void) { int fd,count; char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff}; while ((fd = open("/dev/my_led",O_RDWR)) < 0) { printf ("pthread_two:Open /dev/my_led file error "); //pthread_exit(0); sleep(1); } for(count=0;count<3;count++) { write(fd,&buf[1],1); sleep(1); write(fd,&buf[5],1); sleep(1); } close(fd); } main() { pthread_t thread_one_id,thread_two_id; int resurt; pthread_attr_t thread_one_attr,thread_two_attr; int thread_one_priority,thread_two_priority; thread_one_priority = 11; thread_two_priority = 11; pthread_attr_init(&thread_one_attr); pthread_attr_init(&thread_two_attr); //设置为指定调度算法 pthread_attr_setinheritsched(&thread_one_attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setinheritsched(&thread_two_attr, PTHREAD_EXPLICIT_SCHED); //指定调度算法 pthread_attr_setschedpolicy(&thread_one_attr, SCHED_RR); pthread_attr_setschedpolicy(&thread_two_attr, SCHED_RR); pthread_attr_setschedparam(&thread_one_attr, (struct sched_param *)&thread_one_priority); pthread_attr_setschedparam(&thread_two_attr, (struct sched_param *)&thread_two_priority); pthread_attr_setdetachstate(&thread_one_attr,PTHREAD_CREATE_JOINABLE); //sleep(1); if((resurt = pthread_create(&thread_one_id, &thread_one_attr, (void *)thread_one, NULL)) == -1) { perror("ss"); printf("thread one creat error %d",resurt); exit(1); } if((resurt = pthread_create(&thread_two_id, &thread_two_attr, (void *)thread_two, NULL))== -1) { printf("thread two creat error "); exit(1); } //sleep(1); pthread_join(thread_one_id, NULL); pthread_join(thread_two_id, NULL); }
运行结果
自旋锁
自旋锁是一种对临界资源进行互斥手访问的典型手段。为了获得一个自旋锁,在某CPU 上运行的代码需先执行一个原子操作,该操作测试并设置(test-and-set)某个内存变量,由于它是原子操作,所以在该操作完成之前其他执行单元不可能访问这个内存变量。
自旋锁保护临界段
spinlock(&lock_led); if (count)/*已经打开*/ { spin_unlock(&lock_led); return -1; } spin_unlock(&lock_led);
信号量
//获得信号量
void down(struct semaphore * sem);
//释放信号量
void up(struct semaphore * sem);
2 .关于阻塞/非阻塞IO
阻塞和非阻塞I/O 是设备访问的两种不同模式,驱动程序可以灵活地支持用户空间对设备的这两种访问方式。
阻塞操作是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。而非阻塞操作的进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。
阻塞一个线程,直至另一个线程运行完。
include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <asm/uaccess.h> /* copy_to_user,copy_from_user */ #include <linux/miscdevice.h> #include <linux/pci.h> #include <mach/map.h> #include <mach/regs-gpio.h> #include <mach/gpio-bank-m.h> #include <plat/gpio-cfg.h> #include <linux/wait.h> #include <linux/sched.h> #define LED_MAJOR 240 struct my_queue { //定义等待列对头 wait_queue_head_t queue_head; //定义自旋锁 spinlock_t lock; //文件打开标志 int file_flag; }led_queue; int led_open (struct inode *inode,struct file *filp) { unsigned tmp; struct my_queue * dev = &led_queue; //自旋锁 临界段 spin_lock(&dev->lock); //定义等待列对 DECLARE_WAITQUEUE(wait,current); //进入等待列对头 add_wait_queue(&dev->queue_head, &wait); dev->file_flag--; spin_unlock(&dev->lock); while(dev->file_flag < 0) { //改变进程状态 __set_current_state(TASK_INTERRUPTIBLE); // schedule(); } spin_lock(&dev->lock); dev->file_flag = 0; spin_unlock(&dev->lock); tmp = readl(S3C64XX_GPMDAT); tmp &= 0xffff0000; tmp |= 0x00001111; writel(tmp, S3C64XX_GPMCON); writel(0xffffffff, S3C64XX_GPMDAT); printk("<0>open led "); //移除 remove_wait_queue(&dev->queue_head, &wait); return 0; } ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos) { return count; } ssize_t led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos) { char wbuf[1]; unsigned tmp; copy_from_user(wbuf,buf,count); tmp = readl(S3C64XX_GPMDAT); tmp &= 0xfffffff0; tmp |= wbuf[0]; writel(tmp, S3C64XX_GPMDAT); return count; } int led_release (struct inode *inode, struct file *filp) { struct my_queue * dev = &led_queue; spin_lock(&dev->lock); dev->file_flag = 1; spin_unlock(&dev->lock); wake_up_interruptible(&dev->queue_head); return 0; } struct file_operations led_fops ={ .owner = THIS_MODULE, .open = led_open, .read = led_read, .write = led_write, .release = led_release, }; int __init led_init (void) { int rc; struct my_queue * dev = &led_queue; printk ("<0>led init "); rc = register_chrdev(LED_MAJOR,"led",&led_fops); if (rc <0) { printk ("<0>register %s char dev error ","led"); return -1; } //初始化列对头 init_waitqueue_head(&dev->queue_head); //初始化自旋锁 spin_lock_init(&dev->lock); //文件打开标志 dev->file_flag = 1; printk ("<0>success "); return 0; } void __exit led_exit (void) { unregister_chrdev(LED_MAJOR,"led"); printk ("<0>module exit "); return ; } module_init(led_init); module_exit(led_exit);
非阻塞,poll轮循
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <asm/uaccess.h> /* copy_to_user,copy_from_user */ #include <linux/miscdevice.h> #include <linux/pci.h> #include <mach/map.h> #include <mach/regs-gpio.h> #include <mach/gpio-bank-m.h> #include <plat/gpio-cfg.h> #include <linux/wait.h> #include <linux/sched.h> #include <linux/poll.h> #define LED_MAJOR 240 struct drive_str { //定义等待列对头 wait_queue_head_t queue_head; //定义自旋锁 spinlock_t lock; //文件打开标志 int file_flag; }led_driver; int led_open (struct inode *inode,struct file *filp) { unsigned tmp; tmp = readl(S3C64XX_GPMDAT); tmp &= 0xffff0000; tmp |= 0x00001111; writel(tmp, S3C64XX_GPMCON); writel(0xffffffff, S3C64XX_GPMDAT); printk("<0>open led "); //移除 return 0; } ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos) { struct drive_str * dev = &led_driver; //自旋锁 临界段 spin_lock(&dev->lock); if(dev->file_flag == 0) return (0); dev->file_flag = 0; spin_unlock(&dev->lock); return (1); } ssize_t led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos) { char wbuf[1]; unsigned tmp; copy_from_user(wbuf,buf,count); tmp = readl(S3C64XX_GPMDAT); tmp &= 0xfffffff0; tmp |= wbuf[0]; writel(tmp, S3C64XX_GPMDAT); return count; } int led_release (struct inode *inode, struct file *filp) { struct drive_str * dev = &led_driver; spin_lock(&dev->lock); dev->file_flag = 1; spin_unlock(&dev->lock); return 0; } static unsigned int led_poll(struct file * filp,poll_table *wait) { unsigned int mask = 0; struct drive_str *dev = &led_driver; poll_wait(filp, &dev->queue_head,wait); if(dev->file_flag) { mask = 1; } return (mask); } struct file_operations led_fops ={ .owner = THIS_MODULE, .open = led_open, .read = led_read, .write = led_write, .release = led_release, .poll = led_poll, }; int __init led_init (void) { int rc; struct drive_str * dev = &led_driver; printk ("<0>led init "); rc = register_chrdev(LED_MAJOR,"led",&led_fops); if (rc <0) { printk ("<0>register %s char dev error ","led"); return -1; } //初始化列对头 init_waitqueue_head(&dev->queue_head); //初始化自旋锁 spin_lock_init(&dev->lock); //文件打开标志 dev->file_flag = 1; printk ("<0>success "); return 0; } void __exit led_exit (void) { unregister_chrdev(LED_MAJOR,"led"); printk ("<0>module exit "); return ; } module_init(led_init); module_exit(led_exit);
测试程序
#include "stdio.h" #include "pthread.h" #include "stdlib.h" #include <fcntl.h> #include "poll.h" void thread_one(void) { int fd,count,ret; char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff}; struct pollfd fds[1]; fd = open("/dev/my_led",O_RDWR); fds[0].fd = fd; fds[0].events = POLLIN; if (fd < 0) { printf ("Open /dev/my_led file error "); pthread_exit(0); } if((ret = read(fd,&buf[1],1)) == 0) { ret = poll(fds,1,10000); if(ret == 0) { printf("time out "); printf("%u ",ret); pthread_exit(0); } } for(count=0;count<3;count++) { write(fd,&buf[0],1); sleep(1); write(fd,&buf[5],1); sleep(1); } close (fd); } void thread_two(void) { int fd,count,ret; char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff}; struct pollfd fds[1]; fd = open("/dev/my_led",O_RDWR); fds[0].fd = fd; fds[0].events = POLLIN; if (fd == 1) { printf ("open /dev/my_led file error "); pthread_exit(0); } if((ret = read(fd,&buf[1],1)) == 0) { ret = poll(fds,1,10000); if(ret == 0) { printf("time out "); printf("%u ",ret); pthread_exit(0); } } for(count=0;count<3;count++) { write(fd,&buf[1],1); sleep(1); write(fd,&buf[5],1); sleep(1); } close(fd); } main() { pthread_t thread_one_id,thread_two_id; int resurt; pthread_attr_t thread_one_attr,thread_two_attr; int thread_one_priority,thread_two_priority; thread_one_priority = 11; thread_two_priority = 11; pthread_attr_init(&thread_one_attr); pthread_attr_init(&thread_two_attr); //设置为指定调度算法 pthread_attr_setinheritsched(&thread_one_attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setinheritsched(&thread_two_attr, PTHREAD_EXPLICIT_SCHED); //指定调度算法 pthread_attr_setschedpolicy(&thread_one_attr, SCHED_RR); pthread_attr_setschedpolicy(&thread_two_attr, SCHED_RR); pthread_attr_setschedparam(&thread_one_attr, (struct sched_param *)&thread_one_priority); pthread_attr_setschedparam(&thread_two_attr, (struct sched_param *)&thread_two_priority); pthread_attr_setdetachstate(&thread_one_attr,PTHREAD_CREATE_JOINABLE); //sleep(1); if((resurt = pthread_create(&thread_one_id, &thread_one_attr, (void *)thread_one, NULL)) == -1) { printf("thread one creat error %d",resurt); exit(1); } if((resurt = pthread_create(&thread_two_id, &thread_two_attr, (void *)thread_two, NULL))== -1) { printf("thread two creat error "); exit(1); } //sleep(1); pthread_join(thread_one_id, NULL); pthread_join(thread_two_id, NULL); }
3.异步通知
使用信号进行进程间通信是UNIX 系统中的一种传统机制。在Linux系统中,异步通知使用信号来实现。
使用异步通知,一个进程结束后发信号给另一个进程
驱动程序:
include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <asm/uaccess.h> /* copy_to_user,copy_from_user */ #include <linux/miscdevice.h> #include <linux/pci.h> #include <mach/map.h> #include <mach/regs-gpio.h> #include <mach/gpio-bank-m.h> #include <plat/gpio-cfg.h> #include <linux/wait.h> #include <linux/sched.h> #include <linux/poll.h> #include <asm/signal.h> #include <asm-generic/siginfo.h> #define LED_MAJOR 240 struct drive_str { struct fasync_struct * async }led_driver; static int led_open (struct inode *inode,struct file *filp) { unsigned tmp; tmp = readl(S3C64XX_GPMDAT); tmp &= 0xffff0000; tmp |= 0x00001111; writel(tmp, S3C64XX_GPMCON); writel(0xffffffff, S3C64XX_GPMDAT); printk("<0>open led "); return 0; } static ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos) { return (count); } static ssize_t led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos) { char wbuf[1]; unsigned tmp; copy_from_user(wbuf,buf,count); tmp = readl(S3C64XX_GPMDAT); tmp &= 0xfffffff0; tmp |= wbuf[0]; writel(tmp, S3C64XX_GPMDAT); return count; } static int led_fasync(int fd,struct file * filp,int mode) { struct drive_str * dev = &led_driver; return (fasync_helper(fd,filp,mode,&dev->async)); } static int led_release (struct inode *inode, struct file *filp) { struct drive_str * dev = &led_driver; kill_fasync(&dev->async,SIGIO, POLL_IN); return (0); } struct file_operations led_fops ={ .owner = THIS_MODULE, .open = led_open, .read = led_read, .write = led_write, .release = led_release, .fasync = led_fasync, }; static int __init led_init (void) { int rc; struct drive_str * dev = &led_driver; printk ("<0>led init "); rc = register_chrdev(LED_MAJOR,"led",&led_fops); if (rc <0) { printk ("<0>register %s char dev error ","led"); return -1; } dev->async = NULL; printk ("<0>success "); return 0; } static void __exit led_exit (void) { unregister_chrdev(LED_MAJOR,"led"); printk ("<0>module exit "); return ; } module_init(led_init); module_exit(led_exit);
测试程序:
#include "stdio.h" #include "pthread.h" #include "stdlib.h" #include <fcntl.h> #include <signal.h> #include <unistd.h> int thread_two_fd; void sign_handler(int signum); void thread_one(void) { int fd,count; char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff}; fd = open("/dev/my_led",O_RDWR); if (fd < 0) { printf ("Open /dev/my_led file error "); pthread_exit(0); } for(count=0;count<3;count++) { write(fd,&buf[0],1); sleep(1); write(fd,&buf[5],1); sleep(1); } close (fd); } void thread_two(void) { int fd,oflags; char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff}; fd = open("/dev/my_led",O_RDWR); if (fd < 0) { printf ("open /dev/my_led file error "); pthread_exit(0); } signal(SIGIO,sign_handler); //改变已打开文件属性 fcntl(fd, F_SETOWN, getpid()); oflags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, oflags | FASYNC); thread_two_fd = fd; pause(); close(fd); } main() { pthread_t thread_one_id,thread_two_id; int resurt; pthread_attr_t thread_one_attr,thread_two_attr; int thread_one_priority,thread_two_priority; thread_one_priority = 11; thread_two_priority = 11; pthread_attr_init(&thread_one_attr); pthread_attr_init(&thread_two_attr); //设置为指定调度算法 pthread_attr_setinheritsched(&thread_one_attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setinheritsched(&thread_two_attr, PTHREAD_EXPLICIT_SCHED); //指定调度算法 pthread_attr_setschedpolicy(&thread_one_attr, SCHED_RR); pthread_attr_setschedpolicy(&thread_two_attr, SCHED_RR); pthread_attr_setschedparam(&thread_one_attr, (struct sched_param *)&thread_one_priority); pthread_attr_setschedparam(&thread_two_attr, (struct sched_param *)&thread_two_priority); pthread_attr_setdetachstate(&thread_one_attr,PTHREAD_CREATE_JOINABLE); //sleep(1); if((resurt = pthread_create(&thread_one_id, &thread_one_attr, (void *)thread_one, NULL)) == -1) { printf("thread one creat error %d",resurt); exit(1); } if((resurt = pthread_create(&thread_two_id, &thread_two_attr, (void *)thread_two, NULL))== -1) { printf("thread two creat error "); exit(1); } //sleep(1); pthread_join(thread_one_id, NULL); pthread_join(thread_two_id, NULL); } void sign_handler(int signum) { int count; char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff}; printf("sign_handle "); for(count=0;count<3;count++) { write(thread_two_fd ,&buf[1],1); sleep(1); write(thread_two_fd ,&buf[5],1); sleep(1); } }