并发与竞争
并发
是指操作系统中,一个时间段中有几个程序都处于启动运行到运行完毕间,且这几个程序都是同一个处理器上运行,但任何一个时间点只有一个程序在处理机器上运行。并发容易导致竞争问题。
竞争
是两个或者多个进程同时访问一个资源,从而引起的资源错误。
原子操作
所谓的原子操作就是该操作系统不会在执行完毕前被任何其他任务或者事件打断。也就是说,原子操作是一种不可以被打断的操作。原子操作需要硬件的支持,因此是架构相关的,其API和原子类型的定义都定义在内核源码的include/asm/atomic.h文件中。
原子要么执行,要么不执行。优点是简单,缺点是只能做技术操作。
typedef struct
{
volatile int counter;
}atomic_t;
关键字volatile用来暗示GCC不要对该类型做数据优化,所以对这个变量counter的访问都是基于内存的,不要将其缓冲到寄存器中。
自旋锁
自旋锁是一种建安的并发控制机制,其是实现信号量和完成量的基础。自旋锁对资源有很好的保护作用,在Linux驱动程序中进程使用,避免竞争条件。
Linux有两种锁,一个是自旋锁,一个是信号量。这两种锁是为了解决内核中遇到的不同问题开发的。
注意:
1. 自旋锁是一种忙等待,对系统性能有影响,是一种轻量级的枷锁机制。
2. 自旋锁不能递归使用,这是因为,自选锁被设计成在不同现成或者函数之间的同步。如果一个线程在已经持有自旋锁时,其处于忙等待状态,则已经没有机会释放自己所持有的锁了。如果这时再调用自身,则自旋锁永远没有机会执行了。
struct spinlock_t
spinlock_t lock = SPIN_LOCK_UNLOCKED;
void spin_lock_init(spinlock_t lock);
void Function()
{
spin_lock(&lock);
/*
***
*/
spin_unlock(&lock);
}
例子:
int count=0;
spinlock_t lock;
int xxxx_init(void)
{
//**
spin_lock(&lock);
//**
}
int xxx_open(struct inode* inode, struct file* filp)
{
//**
spin_lock(&lock);
if(count)
{
spin_unlock(&lock);
return -EBUSY;
}
count ++;
spin_unlock(&lock);
//***
}
int xxx_release(strut inode* inode, struct file* filp)
{
//**
spin_lock(&lock);
count++;
spin_unlock(&lock);
//**
}
信号量
Linux提供了两种信号量,一种用于内核程序中个,一种用于应用程序中。
信号量只有当得到信号量的进程或者线程才能进入临界区,执行临界代码。信号量与自旋锁的最大的不同在于,当一个进程试图获取一个已经锁定的信号量时,进程不会像自旋锁一样处于忙等待。
从信号量的原理上来说,没有获得信号量的函数可能睡眠。这就要求只有能够睡眠的进程才能使用信号量,不能睡眠的进程不能使用信号量。
struct seamphore
{
spinlock_t lock; //对count变量的保护,count变化时,锁定
unsigned int count;
struct list_heat wait_list;
};
count = 0:表示信号量被其他进程使用,现在不可以用这个信号量,但是wait_list队列中没有进程在等待信号量
count <0:表示至少有一个进程在wait_list队列中等待信号量被释放;
count>0:表示这个信号量是空闲的,程序可以使用这个信号量;
struct semaphore sem;
static inline void sema_init(struct semphore* sem, int val);
#define init_MUTEX(sem) sema_init(sem,1)
#define init_MUTEX_LOCKED(sem) sem_init(sem,0);
void down(struct semphore* sem);
void down_interruptible(struct sempaphore* sem);
void up(struct semaphore* sem);
int xxx_init(void)
{
//
init_MUTEX(&lock);
//
}
int xxx_open(struct inode* inode ,struct file* filp)
{
//
down(&sem);
//
return 0;
}
int xxx_release(struct inode* inode, struct file* filp)
{
//
up(&sem);
//
}
完成量
struct completion
{
unsigned int done;
wait_queue_heat_t wait;
};
struct completion com;
int xxx_init(void)
{
//
init_completion(&com);
//
}
int xxx_A()
{
//
wait_for_completion(&com);
//
return 0;
}
int xxx_B()
{
//
complete(&com);
//
}