信号量机制DOWN操作和UP操作的详细说明

DOWN操作:linux内核。信号DOWN例如,下面的操作:

  • void down(struct semaphore *sem); //不间断
  • int down_interruptible(struct semaphore *sem);//可中断
  • int down_killable(struct semaphore *sem);//睡眠的进程能够由于受到致命信号而被唤醒,中断获取信号量的操作。

  • int down_trylock(struct semaphore *sem);//试图获取信号量,若无法获得则直接返回1而不睡眠。

    返回0则 表示获取到了信号量

  • int down_timeout(struct semaphore *sem,long jiffies);//表示睡眠时间是有限制的。假设在jiffies指明的时间到期时仍然无法获得信号量,则将返回错误码。

在以上四种函数中,驱动程序使用的最频繁的就是down_interruptible函数,下面将对该函数进行分析。

down_interruptible函数的定义例如以下:

int down_interruptible(struct semaphore *sem)
{
       unsigned long flags;
       int result = 0;
       spin_lock_irqsave(&sem->lock,flags);
       if (likely(sem->count> 0))
              sem->count--;
       else
              result =__down_interruptible(sem);
       spin_unlock_irqrestore(&sem->lock,flags);
       return result;
}

函数分析:函数首先通过spin_lock_irqsave的调用来保证对sem->count操作的原子性。假设count>0。表示当前进程能够获得信号量,将count的值减1然后退出。

假设count不大于0,表明当前进程无法获取信号量,则调用__down_interruptible,后者会继续调用__down_common。

__down_common 函数定义例如以下:

static inline int __sched __down_common(struct semaphore *sem, longstate,
                                                        longtimeout)
{
       struct task_struct *task= current;
       struct semaphore_waiterwaiter;
       list_add_tail(&waiter.list,&sem->wait_list);
       waiter.task = task;
       waiter.up = 0;
       for (;;) {
              if(signal_pending_state(state, task))
                     gotointerrupted;
              if (timeout <=0)
                     gototimed_out;
              __set_task_state(task,state);
              spin_unlock_irq(&sem->lock);
              timeout =schedule_timeout(timeout);
              spin_lock_irq(&sem->lock);
              if (waiter.up)
                     return 0;
       }
 timed_out:
       list_del(&waiter.list);
       return -ETIME;
 interrupted:
       list_del(&waiter.list);
       return -EINTR;
}

函数分析:在__down_common函数数运行了下面操作。

(1)将当前进程放到信号量成员变量wait_list所管理的队列中。

(2)在一个for循环中把当前的进程状态这是为TASK_INTERRUPTIBLE,在调用schedule_timeout使当前进程进入睡眠状态。函数将停留在schedule_timeout调用上,知道再次被调度运行。

(3) 当该进程再一次被调度时,按原因运行对应的操作:假设waiter.up不为0说明进程被该信号量的up操作所唤醒,进程能够获得信号量。假设进程是由于被用户空间的信号所中断或超时信号所引起的唤醒。则返回对应的错误代码。

UP操作:LINUX内核仅仅提供了一个up函数

up函数定义例如以下:

void up(struct semaphore *sem)
{
       unsigned long flags;

       spin_lock_irqsave(&sem->lock,flags);
       if(likely(list_empty(&sem->wait_list)))
              sem->count++;
       else
              __up(sem);
       spin_unlock_irqrestore(&sem->lock,flags);
}

函数分析:假设sem的wait_list队列为空,则表明没有其它进程正在等待该信号量,那么仅仅须要把sem的count加1就可以。假设wait_list队列不为空,则说明有其它进程正睡眠在wait_list上等待该信号。此时调用__up(sem)来唤醒进程:

__up()函数定义例如以下:

static noinline void __sched __up(struct semaphore *sem)
{
       struct semaphore_waiter*waiter = list_first_entry(&sem->wait_list,
                                          structsemaphore_waiter, list);
       list_del(&waiter->list);
       waiter->up = 1;
       wake_up_process(waiter->task);
}

函数分析:在函数中,调用了wake_up_process来唤醒进程,这样进程就从之前的__down_interruptible调用中的timeout=schedule_timeout(timeout)处醒来,wait-up=1, __down_interruptible返回0。进程获得了信号量。

up()与down()函数之间的联系:由上面对两个函数的分析能够知道,__down_common函数中timeout=schedule_timeout(timeout) 它具有非常重要的数据。

版权声明:本文博主原创文章,博客,未经同意不得转载。

时间: 2024-12-20 01:06:00

信号量机制DOWN操作和UP操作的详细说明的相关文章

信号量机制中的DOWN操作与UP操作详解

DOWN操作:linux内核中,对信号量的DOWN操作有如下几种: void down(struct semaphore *sem); //不可中断 int down_interruptible(struct semaphore *sem);//可中断 int down_killable(struct semaphore *sem);//睡眠的进程可以因为受到致命信号而被唤醒,中断获取信号量的操作. int down_trylock(struct semaphore *sem);//试图获取信号

【操作系统总结】进程同步的信号量机制

信号量机制是由dijkstra 1965年提出,是解决进程同步重要的工具 下面方法适用与几个进程访问同一个临界区 整形信号量 定义一个表示资源数目的整形信号量S,仅能同步P, V操作改变.原始值S=1,每一个进程来的时候会执行: 首先执行wait()操作,如果信号量s<=0就会一直检测并阻塞 如果不小于0就会进入临界区,并把S设为0,保证其他进程无法进去临界区 在临界区执行完,再把信号量设置回来. wait(S) { while(S <= 0);//资源如果小余0就会阻塞.一直在这边检测 S-

信号量机制

11.1 2 个程序的例子 先看 2 个程序: #include<unistd.h> int main(void) { allarm(10); for(;;;); } 这段程序的含义比较明显:这个程序在一个无限循环中,直到过了 10 秒,之后 程序被终止. 在来看另外一个程序: Static void setvalue(void) { Flag=1; } int main(void) { int sum=0; int flag=0; struct sigaction act; act.sa_h

操作系统之信号量机制总结

1965年,荷兰学者Djikstra提出信号量(Semaphores)机制是一种卓有成效的进程同步工具.在长期的应用中,信号量机制又获得了很大的发展,从整型信号量记录型信号量,进而发展成"信号量集"机制,下面我们来讨论一下各种信号量机制的内容. 1.整形信号量(经典的PV操作:P(wait):申请资源 V(signal):释放资源) 1 wait(S):while S<=0 do no-op; 2 S:=S-1; 3 signal(S): S:=S+1 2.记录型信号量 在整形信

Python之路-(Django(csrf,中间件,缓存,信号,Model操作,Form操作))

csrf 中间件 缓存 信号 Model操作 Form操作 csrf: 用 django 有多久,我跟 csrf 这个概念打交道就有久了. 每次初始化一个项目时都能看到 django.middleware.csrf.CsrfViewMiddleware 这个中间件 每次在模板里写 form 时都知道要加一个 {% csrf_token %} tag 每次发 ajax POST 请求,都需要加一个 X_CSRFTOKEN 的 header 什么是 CSRF CSRF, Cross Site Req

Qt--文本流和数据流、缓冲操作和数据操作

一.文本流和数据流 A.Qt中讲文件类型分为2大类1.文本文件--文件内容是可读的文本字符2.数据文件--文件内容是直接的二进制数据QFile直接支持文本文件和数据文件的读写B.Qt提供了辅助类简化了文本文件/数据文件的读写1.QTextStream--写入的数据全部转换为可读文本2.QDataStream--写入的数据根据类型转换为二进制数据IO设备辅助类的使用方式不同的Qt版本的数据流文件格式可能不同void setVersion(int v)//设置的版本号int version()con

atitit.浏览器web gui操作类库 和 操作chrome浏览器的类库使用总结

atitit.浏览器web gui操作类库 和 操作chrome浏览器的类库使用总结 1. 常见标准 1 1.1. 录制重放 1 1.2. 一个窗体一个proxy cookie 1 1.3. exec js 1 1.4. js 调用java 1 1.5. 修改dom属性 2 1.6. 关键字驱动 2 1.7. 加载js类库 2 1.8. 一个窗口一个代理 2 1.9. 独立窗口cookie 2 1.10. 无图模式支持 2 1.11. 支持自定义路径 2 2. 框架选型selenium2(web

ubuntu命令行操作mysql常用操作

登陆mysql [email protected]:~/ruby/mydiary$ mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. 查看所有的数据库 mysql> show databases; --注意必须要用;结尾否则不会立即执行代码 +--------------------+ | Database | +--------------------+ | inf

ThinkPHP - 前置操作+后置操作

前置操作和后置操作 系统会检测当前操作(不仅仅是index操作,其他操作一样可以使用)是否具有前置和后置操作,如果存在就会按照顺序执行,前置和后置操作的方法名是在要执行的方法前面加 _before_和_after_,例如: class CityAction extends Action{ //前置操作方法 public function _before_index(){ echo 'before<br/>'; } public function index(){ echo 'index<

JAVA的IO操作:内存操作流

掌握内存操作流 输入和输出都是从文件中来的,当然,也可将输出的位置设置在内存上,这就需要ByteArrayInputStream和ByteArrayOutputStream ByteArrayInputStream:将内容写入到内存中, ByteArrayOutputStream:将内存中数据输出 此时的操作应该以内存为操作点. 利用此类 完成一些功能. 常用方法 ByteArrayInputStream :是InputStream子类. public class ByteArrayInputS