**
1.自旋锁:
:**Linux中最常见的锁,在短时间内进行清亮级加锁。如果一个执行线程试图获取一个已经被持有的自旋锁,那么该线程就会一直进行忙循环——旋转——等待锁重新可用。
注意:自旋锁在Linux不可递归(当试图获取一个自己已经持有的锁时,本身在自旋等待自己释放锁,这时候自己将永远无法释放锁,会造成死锁的情况。)
1.2读写自旋锁:
用途明确分为读取和写入(内核中任务链表的保护就是由读写自旋锁实现的)一个或多个读任务可以并发的持有读锁,但是写锁只能最多被一个写任务持有,且不能有并发的读操作。
注意:当将一个读锁升级为写锁时,会造成死锁。写锁只能在读锁完全被释放的情况下才能被获得。
以上两种锁适用于加锁的时间比较短,且代码不会睡眠(中断处理程序)。
1.3信号量:
Linux中的信号量是一种睡眠锁,当一个任务试图获得一个被占用的信号量时,它会被推进一个等待对列,然后让其睡眠。当这个信号量被释放时,等待队列中的一个任务被唤醒,且持有此信号量。
一个信号量可以被多个任务所持有,但是通常情况下在一个时刻只允许一个锁的持有者,这时计数器等于1,也称为二值信号量因为只有0个或者1个持有锁。当初始化信号量时将可持有者数设置为大于1个时,这时信号量被称为计数信号量。下面是用信号量写的一个生产者消费者模型:
int main(void)
{
int*addr=mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);
if(addr==MAP_FAILED)
{
perror(“mmap”);
exit(-1);
}
//信号量
int semid=semget(ftok(“.”,100),2,IPC_CREAT|0666);
semctl(semid,0,SETVAL,0); //0号信号量用来读
semctl(semid,1,SETVAL,1); //1号信号量用来写
struct sembuf sem_r_v={0,1,0}; //释放
struct sembuf sem_r_p={0,-1,0};//获取
struct sembuf sem_w_v={1,1,0}; //释放
struct sembuf sem_w_p={1,-1,0};//获取
if(fork()>0)//生产者
{
int i=0;
while(i<100)
{
semop(semid,&sem_w_p,1);//获取写锁
//生产
*addr=i++;
printf("产品已生产,%d\n",*addr);
sleep(1);
semop(semid,&sem_r_v,1);//释放读锁
}
}
else
{
while(1)
{
semop(semid,&sem_r_p,1); //获取读锁
//消费
printf("产品已消费,%d\n",*addr);
sleep(1);
semop(semid,&sem_w_v,1);//释放写锁
}
}
}