定义在头文件linux/semaphore.h中;
信号量(semaphore)是用于保护临界区的一种常用方法,它的使用方式与自旋锁类似;与自旋锁相同,只有得到信号量的进程才能执行临界区的代码;但是,与自旋锁不同的是,当获取不到信号量的时候,进程不会在原地打转,而是进入休眠等待状态;
1).定义信号量:
struct semaphore sem;
2).初始化信号量:
void sema_init(struct semaphore* sem, int val):
该函数用于初始化信号量sem,并设置信号量sem的值为val;尽管信号量的值可以被初始化为大于1的值,从而成为一个计数信号量,但是通常并不这样用;
void init_MUTEX(struct semaphore* sem):
该函数用于初始化一个用作互斥的信号量sem,它把信号量sem的值设置为1,等同于sema_init(struct semaphore* sem, 1);
void init_MUTEX_LOCKED(struct semaphore* sem):
该函数用于初始化一个信号量sem,但是它把信号量sem的值设置为0,等同于sema_init(struct semaphore* sem, 0);
此外,下面两个宏是用于定义并初始化信号量的快捷方式:
DECLARE_MUTEX(name); //定义名为name的信号量,并设置初始值为1;
DECLARE_MUTEX_LOCKED(name); //定义名为name的信号量,并设置初始值为0;
3).获得信号量:
void down(struct semaphore* sem):
该函数用于获得信号量sem,但是它会导致调用进程睡眠,因此,不能在中断上下文中使用;该函数把信号量sem的值减1,如果信号量sem的值为非负(>0),则函数立即返回,否则将被永远挂起,直到其它执行单元释放该信号量sem之后,才能继续运行下去;
void down_interruptible(struct semaphore* sem):
该函数的功能与down()类似,也是用于获得信号量sem;不同之处在于,因为down()函数而进入睡眠状态的进程不能被信号打断,而因为down_interruptible()函数而进入睡眠状态的进程能够被信号打断,信号也会导致该函数返回,这个时候函数的返回值为非0;如果函数返回0,则表示获得信号量正常返回;如果被信号打断,则返回-EINTR;
int down_killable(struct semaphore* sem):
该函数用于获得信号量sem;但是它可以被kill信号打断;
int down_timeout(struct semaphore* sem, long jiffies):
该函数用于获得信号量sem,它与down()一样,也会导致调用进程睡眠,因此,也不能用于中断上下文;但是它与down()不同的是,在得不到信号量时,该函数不会一直睡眠下去,它只会睡眠一个指定的超时时间jiffies,当该超时时间到达时,仍然没有获得信号量的话,该函数就返回;超时时间jiffies是以系统时钟滴答次数计算;
int down_trylock(struct semaphore* sem):
该函数尝试获得信号量sem,如果能够立即获得,它就获得该信号量并立即返回0,否则,立即返回非0值;不管能不能获得信号量,该函数都会立即返回,所以,它不会导致调用进程睡眠,可以在中断上下文中使用;
注意:在使用down_interruptible()获得信号量的时候,一般都要对返回值进行检查,如果返回非0值,则表示是被信号打断了,通常立即返回-ERESTARTSYS;如:
if(down_interruptible(&sem)) //被信号打断;
{
return -ERESTARTSYS;
}
4).释放信号量:
void up(struct semaphore* sem):该函数用于释放信号量sem,并唤醒等待者;该函数把信号量sem的值加1,如果信号量sem的值为非正数,则表示有其它执行单元在等待该信号量sem,因此唤醒这些等待者;
5).信号量的使用模式:
struct semaphore my_sem;
sema_init(&my_sem, val);
down(&sem); //获得信号量,保护临界区;
...... //临界区操作
up(&mount_sem); //释放信号量;
备注:如果信号量的值被初始化为0,则它可以用于同步;同步就意味着一个执行单元的继续执行需要等待另一个执行单元完成某事,保证执行的先后顺序;
例子:
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/delay.h>
//这三个头文件与内核线程的使用有关;
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/err.h>
//信号量相关
#include <linux/semaphore.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("*************");
MODULE_VERSION("2.6.35.000");
static int sleep_time = (1*10*HZ);
static int shared_res = 0;
//STEP1:定义信号量
struct semaphore my_sem;
//STEP5:实现线程函数
static int thread_process1(void* param)
{
//int val = 0, ret = 0;
while(1)
{
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop())
{
printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);
break;
}
//STEP3:对临界区加锁
down(&my_sem);
//down_interruptible(&my_sem); //need to check the return value of it;
//down_timeout(&my_sem, 10*HZ); //need to check the return value of it;
shared_res++;
//STEP4:对临界区解锁
up(&my_sem);
mdelay(sleep_time);
}
return 12;
};
static int thread_process2(void* param)
{
//int val = 0, ret = 0;
while(1)
{
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop())
{
printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);
break;
}
//STEP3:对临界区加锁
down(&my_sem);
//down_interruptible(&my_sem); //need to check the return value of it;
//down_timeout(&my_sem, 10*HZ); //need to check the return value of it;
shared_res++;
//STEP4:对临界区解锁
up(&my_sem);
msleep(sleep_time);
}
return 34;
};
static int thread_process3(void* param)
{
int val = 0;//, ret = 0;
while(1)
{
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop())
{
printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);
break;
}
//STEP3:对临界区加锁
down(&my_sem);
//down_interruptible(&my_sem); //need to check the return value of it;
//down_timeout(&my_sem, 10*HZ); //need to check the return value of it;
val = shared_res;
printk("%s: shared resource = %d;\n%s", __FUNCTION__, val, ((val % 3) ? "" : "\n"));
//STEP4:对临界区解锁
up(&my_sem);
msleep(sleep_time);
}
return 56;
};
static int thread_process4(void* param)
{
int val = 0;//, ret = 0;
while(1)
{
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop())
{
printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);
break;
}
//STEP3:对临界区加锁
down(&my_sem);
//down_interruptible(&my_sem); //need to check the return value of it;
//down_timeout(&my_sem, 10*HZ); //need to check the return value of it;
val = shared_res;
printk("%s: shared resource = %d;\n%s", __FUNCTION__, val, ((val % 3) ? "" : "\n"));
//STEP4:对临界区解锁
up(&my_sem);
msleep(sleep_time);
}
return 78;
};
static struct task_struct* my_thread1 = NULL;
static struct task_struct* my_thread2 = NULL;
static struct task_struct* my_thread3 = NULL;
static struct task_struct* my_thread4 = NULL;
static int __init study_init(void)
{
int err = 0;
printk("%s\n", __PRETTY_FUNCTION__);
//STEP2:初始化信号量
sema_init(&my_sem, 1);
printk("init semaphore ok\n");
my_thread1 = kthread_create(thread_process1, NULL, "my_thread1");
if(IS_ERR(my_thread1))
{
err = PTR_ERR(my_thread1);
my_thread1 = NULL;
printk(KERN_ERR "unable to start kernel thread1:%d\n", err);
return err;
}
my_thread2 = kthread_create(thread_process2, NULL, "my_thread2");
if(IS_ERR(my_thread2))
{
err = PTR_ERR(my_thread2);
my_thread2 = NULL;
printk(KERN_ERR "unable to start kernel thread2:%d\n", err);
return err;
}
my_thread3 = kthread_create(thread_process3, NULL, "my_thread3");
if(IS_ERR(my_thread3))
{
err = PTR_ERR(my_thread3);
my_thread3 = NULL;
printk(KERN_ERR "unable to start kernel thread3:%d\n", err);
return err;
}
my_thread4 = kthread_create(thread_process4, NULL, "my_thread4");
if(IS_ERR(my_thread4))
{
err = PTR_ERR(my_thread4);
my_thread4 = NULL;
printk(KERN_ERR "unable to start kernel thread4:%d\n", err);
return err;
}
wake_up_process(my_thread1);
wake_up_process(my_thread2);
wake_up_process(my_thread3);
wake_up_process(my_thread4);
printk("%s:all kernel thread start;\n", __FUNCTION__);
return 0;
}
static void __exit study_exit(void)
{
int ret = -1;
printk("%s\n",__PRETTY_FUNCTION__);
if(my_thread1)
{
ret = kthread_stop(my_thread1);
my_thread1 = NULL;
printk("kernel thread1 stop,exit code is %d;\n",ret);
}
if(my_thread2)
{
ret = kthread_stop(my_thread2);
my_thread2 = NULL;
printk("kernel thread2 stop,exit code is %d;\n",ret);
}
if(my_thread3)
{
ret = kthread_stop(my_thread3);
my_thread3 = NULL;
printk("kernel thread3 stop,exit code is %d;\n",ret);
}
if(my_thread4)
{
ret = kthread_stop(my_thread4);
my_thread4 = NULL;
printk("kernel thread4 stop,exit code is %d;\n",ret);
}
printk("%s:all kernel thread stop;\n", __FUNCTION__);
}
module_init(study_init);
module_exit(study_exit);