精华内容
下载资源
问答
  • linux进程的几种状态

    千次阅读 2016-09-12 22:15:02
    1、TASK_RUNNING:(R) 进程当前正在运行,或者正在运行队列中等待调度。只有在该状态的进程才可能在CPU上运行,同一时刻可能有...当这些事件发生时,对应的等待队列中的一个或多个进程将被唤醒。一般情况下,进程列

    1、TASK_RUNNING:(R)
    进程当前正在运行,或者正在运行队列中等待调度。只有在该状态的进程才可能在CPU上运行,同一时刻可能有多个进程处于可执行状态。

    2、TASK_INTERRUPTIBLE:(S)
    进程处于睡眠状态,处于这个状态的进程因为等待某事件的发生(比如等待socket连接、等待信号量),而被挂起。当这些事件发生时,对应的等待队列中的一个或多个进程将被唤醒。一般情况下,进程列表中的绝大多数进程都处于TASK_INTERRUPTIBLE状态。进程可以被信号中断。接收到信号或被显式的唤醒呼叫唤醒之后,进程将转变为 TASK_RUNNING 状态。

    3、TASK_UNINTERRUPTIBLE:(D)
    不可中断的睡眠状态,此进程状态类似于 TASK_INTERRUPTIBLE,只是它不会处理信号。不可中断,指的是进程不响应异步信号,无法用kill命令关闭处于TASK_UNINTERRUPTIBLE状态的进程。中断处于这种状态的进程是不合适的,因为它可能正在完成某些重要的任务。 当它所等待的事件发生时,进程将被显式的唤醒呼叫唤醒。可处理signal, 有延迟

    4、TASK_STOPPED:
    进程已中止执行,它没有运行,并且不能运行。接收到 SIGSTOP 和 SIGTSTP 等信号时,进程将进入这种状态。接收到 SIGCONT 信号之后,进程将再次变得可运行。

    5、TASK_TRACED:(T)
    正被调试程序等其他进程监控时,进程将进入这种状态。

    6、EXIT_ZOMBIE:(Z)
    进程已终止,它正等待其父进程收集关于它的一些统计信息。不可被kill, 即不响应任务信号, 无法用SIGKILL杀死

    7、EXIT_DEAD:(X)
    最终状态(正如其名)。将进程从系统中删除时,它将进入此状态,因为其父进程已经通过 wait4() 或 waitpid() 调用收集了所有统计信息。EXIT_DEAD状态是非常短暂的,几乎不可能通过ps命令捕捉到。

    8、TASK_KILLABLE:
    Linux® kernel 2.6.25 引入了这种进程状态,用于将进程置为睡眠状态,它可以替代有效但可能无法终止的 TASK_UNINTERRUPTIBLE 进程状态,以及易于唤醒但更加安全的 TASK_INTERRUPTIBLE 进程状态

    展开全文
  • Linux的进程状态

    2020-10-02 22:39:22
    在Linux系统中,一个进程被创建之后,在系统中可以有下面5种状态。进程的当前状态记录在进程控制块的state成员中。 Linux的五种进程状态: R running or runnable (on run queue) 正在执行或者可执行,此时进程位于...

    在Linux系统中,一个进程被创建之后,在系统中可以有下面5种状态。进程的当前状态记录在进程控制块的state成员中。
    Linux的五种进程状态:

    R running or runnable (on run queue)
    正在执行或者可执行,此时进程位于执行队列中。状态标志state的值为TASK_RUNNING.
    D uninterruptible sleep (usually I/O)
    不可中断阻塞,通常为 IO 阻塞。状态标志state的值为TASK_UNINTERRUPTIBL。此时,进程也处于等待资源状态。一旦资源有效,进程会立即进入就绪状态。这个等待状态与可中断等待状态的区别在于:处于TASK_UNINTERRUPTIBL状态的进程不能被信号量或者中断所唤醒,只有当它申请的资源有效时才能被唤醒。
    S interruptible sleep (waiting for an event to complete)
    可中断阻塞,此时进程正在等待某个事件完成。状态标志state的值为TASK_INTERRUPTIBL。此时,由于进程未获得它所申请的资源而处在等待状态。一旦资源有效或者有唤醒信号,进程会立即结束等待而进入就绪状态。
    Z zombie (terminated but not reaped by its parent)
    僵死,进程已经终止但是尚未被其父进程获取信息。状态标志state的值为TASK_DEAD。
    T stopped (either by a job control signal or because it is being traced)
    结束,进程既可以被作业控制信号结束,也可能是正在被追踪。状态标志state的值为TASK_STOPPED。

    展开全文
  • Linux 进程控制——等待队列详解

    万次阅读 多人点赞 2016-06-29 21:48:24
    一个进程被置为睡眠, 它被标识为处于一个特殊的状态并且从调度器的运行队列中去除. 直到发生某些事情改变了那个状态, 这个进程将不被在任何 CPU 上调度, 并且, 因此, 将不会运行. 一个睡着的进程已被搁置到系统的...

    一、什么是睡眠

        对于一个进程"睡眠"意味着什么? 当一个进程被置为睡眠, 它被标识为处于一个特殊的状态并且从调度器的运行队列中去除. 直到发生某些事情改变了那个状态, 这个进程将不被在任何 CPU 上调度, 并且, 因此, 将不会运行. 一个睡着的进程已被搁置到系统的一边, 等待以后发生事件.

        LDD3说得很玄乎,睡眠是“自愿调度”,其实就是将当前进程的状态设置为 TASK_INTERRUPTIBLE 等状态,然后schedule() 让出CPU1,让调度器重新选择一个进程来执行。

        对于一个 Linux 驱动使一个进程睡眠是一个容易做的事情. 但是, 有几个规则必须记住以安全的方式编码睡眠.

    这些规则的第一个是: 当你运行在原子上下文时不能睡眠.  

        一个另外的相关的点, 当然, 是你的进程不能睡眠除非确信其他人, 在某处的, 将唤醒它.做唤醒工作的代码必须也能够找到你的进程来做它的工作. 确保一个唤醒发生, 是深入考虑你的代码和对于每次睡眠, 确切知道什么系列的事件将结束那次睡眠.使你的进程可能被找到, 真正地, 通过一个称为等待队列的数据结构实现的. 一个等待队列就是它听起来的样子:一个进程列表, 都等待一个特定的事件.


    二、如何睡眠

        在 Linux 中, 一个等待队列由一个"等待队列头"来管理, 一个 wait_queue_head_t 类型的结构, 定义在<linux/wait.h>中. 一个等待队列头可被定义和初始化, 使用:

        DECLARE_WAIT_QUEUE_HEAD(name); 
    

        或者动态地, 如下:

        wait_queue_head_t my_queue;
        init_waitqueue_head(&my_queue);

      1、简单睡眠    

        Linux 内核中睡眠的最简单方式是一个宏定义, 称为 wait_event(有几个变体); 它结合了处理睡眠的细节和进程在等待的条件的检查. wait_event 的形式是:

        wait_event(queue, condition)
        wait_event_interruptible(queue, condition)
        wait_event_timeout(queue, condition, timeout)
        wait_event_interruptible_timeout(queue, condition, timeout)
        这些东西如何使用?queue 是等待队列头,condition 是条件,如果调用 wait_event 前 condition == 0 ,则调用 wait_event 之后,当前进程就会休眠。
        那么它们四个又有什么不同?
        wait_event:将当前进程的状态设置为 TASK_UNINTERRUPTIBLE  ,然后 schedule()
        wait_event_interruptible:         TASK_INTERRUPTIBLE    ,然后 schedule()
        wait_event_timeout:               TASK_UNINTERRUPTIBLE  ,然后 schedule_timeout()
        wait_event_interruptible_timeout:  TASK_INTERRUPTIBLE    , 然后 schedule_timeout()
        TASK_INTERRUPTIBLE 与 TASK_UNINTERRUPTIBLE 区别在于,它的休眠是否会被信号打断,别的进程发来一个信号比如 kill ,TASK_INTERRUPTIBLE 就会醒来去处理。然而 TASK_UNINTERRUPTIBLE 不会。schedule(),进程调度,而schedule_timeout()进行调度之后,一定时间后自动唤醒
        对应于不同的进程状态,使用不同的唤醒函数:
        void wake_up(wait_queue_head_t *queue);
        void wake_up_interruptible(wait_queue_head_t *queue);
        唤醒时很有意思,比如你调用 wake_up 去唤醒一个使用 wait_event 等,进入休眠的进程,唤醒之后,它会判断 condition 是否为真,如果还是假的继续睡眠。至于为什么这个样子,后面分析代码就会明白。
      
      2、手动睡眠
        DECLARE_WAITQUEUE(name, tsk)  创建一个等待队列:
            tsk一般为当前进行current. 这个宏定义并初始化一个名为name的等待队列.
    
     将等待队列头 加入/移除 等待队列:
            void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
            void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait);
            void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
    

        设置进程状态:

            set_current_state(TASK_INTERRUPTIBLE) 等

        进程调度:  
            schedule() 或者 schedule_timeout()


    三、内核如何实现

        以 wait_event 为例,我们看看内核都干了些什么。

    #define wait_event(wq, condition) 					\
    do {									\
    	if (condition)	 						\
    		break;							\
    	__wait_event(wq, condition);					\
    } while (0)
    #define __wait_event(wq, condition) 					\
    do {									\
    	DEFINE_WAIT(__wait);						\
    									\
    	for (;;) {							\
    		prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);	\
    		if (condition)						\
    			break;						\
    		schedule();						\
    	}								\
    	finish_wait(&wq, &__wait);					\
    } while (0)
    #define DEFINE_WAIT(name)						\
    	wait_queue_t name = {						\
    		.private	= current,				\
    		.func		= autoremove_wake_function,		\
    		.task_list	= LIST_HEAD_INIT((name).task_list),	\
    	}
    typedef struct __wait_queue wait_queue_t;	
    struct __wait_queue {
    	unsigned int flags;
    #define WQ_FLAG_EXCLUSIVE	0x01
    	void *private;
    	wait_queue_func_t func;
    	struct list_head task_list;
    };
    举个例子:宏展开之后
    __wait_event(wq, condition);
    wait_queue_t __wait = {						\
    		.private	= current,				\
    		.func		= autoremove_wake_function,		\
    		.task_list	= LIST_HEAD_INIT((__wait).task_list),	\
    	}
    	for (;;) {							\
    		prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);	\
    		if (condition)						\
    			break;						\
    		schedule();						\
    	}								\
    	finish_wait(&wq, &__wait);
        其实,它定义了一个叫 __wait 的等待队列,private 指向当前进程的 task_struct 结构体(唤醒的时候好知道是哪个进程),然后调用 prepare_to_wait 将等待队列头加入到等待队列中去,并设置当前进程的状态为TASK_UNINTERRUPTIBLE。然后,如果 condition 为假,则schedule(),进程调度的时候,当前进程的状态不是 TASK_RUNNING 必然要被移除 “运行队列”,也就永远不会被调度除非直到醒来。如果 condition 为真,那么finish_wait 会把之前的工作都还原,你继续执行吧,你要的条件都满足了,你还休眠个屁!

        涉及的函数代码贴一贴

    void fastcall
    prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
    {
    	unsigned long flags;
    
    	wait->flags &= ~WQ_FLAG_EXCLUSIVE;
    	spin_lock_irqsave(&q->lock, flags);
    	if (list_empty(&wait->task_list))
    		__add_wait_queue(q, wait);
    	/*
    	 * don't alter the task state if this is just going to
    	 * queue an async wait queue callback
    	 */
    	if (is_sync_wait(wait))
    		set_current_state(state);
    	spin_unlock_irqrestore(&q->lock, flags);
    }
    void fastcall finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
    {
    	unsigned long flags;
    
    	__set_current_state(TASK_RUNNING);
    
    	if (!list_empty_careful(&wait->task_list)) {
    		spin_lock_irqsave(&q->lock, flags);
    		list_del_init(&wait->task_list);
    		spin_unlock_irqrestore(&q->lock, flags);
    	}
    }
        下面来看看如何唤醒的

    #define wake_up(x) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, NULL)
    void fastcall __wake_up(wait_queue_head_t *q, unsigned int mode,
    			int nr_exclusive, void *key)
    {
    	unsigned long flags;
    
    	spin_lock_irqsave(&q->lock, flags);
    	__wake_up_common(q, mode, nr_exclusive, 0, key);
    	spin_unlock_irqrestore(&q->lock, flags);
    }
    static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
    			     int nr_exclusive, int sync, void *key)
    {
    	struct list_head *tmp, *next;
    
    	list_for_each_safe(tmp, next, &q->task_list) {
    		wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);
    		unsigned flags = curr->flags;
    
    		if (curr->func(curr, mode, sync, key) &&
    				(flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
    			break;
    	}
    }
       此时会调用到,我们在等待队列里指定的那个 func 函数,也就是 autoremove_wake_function
    int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
    {
    	int ret = default_wake_function(wait, mode, sync, key);
    
    	if (ret)
    		list_del_init(&wait->task_list);
    	return ret;
    }
    int default_wake_function(wait_queue_t *curr, unsigned mode, int sync,
    			  void *key)
    {
    	return try_to_wake_up(curr->private, mode, sync);
    }
       最终调用到 default_wake_function 来唤醒 等待队列里 private 里指定的那个进程。然后,移除将等待队列头移除等待队列。try_to_wake_up ,会将 要唤醒进程的 进程状态设置为 TASK_RUNNING ,然后放到 “运行队列”中。

    有意思的是:

        我们休眠时,schedule() 在哪里? TMD 居然在 for 循环里

    	for (;;) {							\
    		prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);	\
    		if (condition)						\
    			break;						\
    		schedule();						\
    	}
        唤醒之后,那么又开始了 prepare_to_wait ,判断 condition ....显然 condition 为真,才会真正的 唤醒。
        理解了他们,对于手动休眠也就很明白了。手动休眠就不用判断什么 condition 了。
    DECLARE_WAITQUEUE(name, tsk)
    tsk一般为当前进行current. 这个宏定义并初始化一个名为name的等待队列.
    
    #define DECLARE_WAITQUEUE(name, tsk)                    \
        wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
    #define __WAITQUEUE_INITIALIZER(name, tsk) {                \
        .private    = tsk,                        \
        .func        = default_wake_function,            \
        .task_list    = { NULL, NULL } }
    	
    void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
    void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait);
    void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
    
    void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
    {
    	unsigned long flags;
    
    	wait->flags &= ~WQ_FLAG_EXCLUSIVE;
    	spin_lock_irqsave(&q->lock, flags);
    	__add_wait_queue(q, wait);
    	spin_unlock_irqrestore(&q->lock, flags);
    }
    
    set_current_state(TASK_INTERRUPTIBLE);  
    schedule();
       简单明了:

        1、创建等待队列、等待队列头

        2、将等待队列头加入到等待队列中去

        3、设置当前进程的进程状态

        4、进程调度~









    展开全文
  • 一个进程被置为睡眠, 它被标识为处于一个特殊的状态并且从调度器的运行队列中去除. 直到发生某些事情改变了那个状态, 这个进程将不被在任何 CPU 上调度, 并且, 因此, 将不会运行. 一个睡着的进程已被搁置到系统的...

    一、什么是睡眠

        对于一个进程"睡眠"意味着什么? 当一个进程被置为睡眠, 它被标识为处于一个特殊的状态并且从调度器的运行队列中去除. 直到发生某些事情改变了那个状态, 这个进程将不被在任何 CPU 上调度, 并且, 因此, 将不会运行. 一个睡着的进程已被搁置到系统的一边, 等待以后发生事件.

        LDD3说得很玄乎,睡眠是“自愿调度”,其实就是将当前进程的状态设置为 TASK_INTERRUPTIBLE 等状态,然后schedule() 让出CPU1,让调度器重新选择一个进程来执行。

        对于一个 Linux 驱动使一个进程睡眠是一个容易做的事情. 但是, 有几个规则必须记住以安全的方式编码睡眠.

    这些规则的第一个是: 当你运行在原子上下文时不能睡眠.  

        一个另外的相关的点, 当然, 是你的进程不能睡眠除非确信其他人, 在某处的, 将唤醒它.做唤醒工作的代码必须也能够找到你的进程来做它的工作. 确保一个唤醒发生, 是深入考虑你的代码和对于每次睡眠, 确切知道什么系列的事件将结束那次睡眠.使你的进程可能被找到, 真正地, 通过一个称为等待队列的数据结构实现的. 一个等待队列就是它听起来的样子:一个进程列表, 都等待一个特定的事件.


    二、如何睡眠

        在 Linux 中, 一个等待队列由一个"等待队列头"来管理, 一个 wait_queue_head_t 类型的结构, 定义在<linux/wait.h>中. 一个等待队列头可被定义和初始化, 使用:

        DECLARE_WAIT_QUEUE_HEAD(name); 
    

        或者动态地, 如下:

        wait_queue_head_t my_queue;
        init_waitqueue_head(&my_queue);

      1、简单睡眠    

        Linux 内核中睡眠的最简单方式是一个宏定义, 称为 wait_event(有几个变体); 它结合了处理睡眠的细节和进程在等待的条件的检查. wait_event 的形式是:

        wait_event(queue, condition)
        wait_event_interruptible(queue, condition)
        wait_event_timeout(queue, condition, timeout)
        wait_event_interruptible_timeout(queue, condition, timeout)
        这些东西如何使用?queue 是等待队列头,condition 是条件,如果调用 wait_event 前 condition == 0 ,则调用 wait_event 之后,当前进程就会休眠。
        那么它们四个又有什么不同?
        wait_event:将当前进程的状态设置为 TASK_UNINTERRUPTIBLE  ,然后 schedule()
        wait_event_interruptible:         TASK_INTERRUPTIBLE    ,然后 schedule()
        wait_event_timeout:               TASK_UNINTERRUPTIBLE  ,然后 schedule_timeout()
        wait_event_interruptible_timeout:  TASK_INTERRUPTIBLE    , 然后 schedule_timeout()
        TASK_INTERRUPTIBLE 与 TASK_UNINTERRUPTIBLE 区别在于,它的休眠是否会被信号打断,别的进程发来一个信号比如 kill ,TASK_INTERRUPTIBLE 就会醒来去处理。然而 TASK_UNINTERRUPTIBLE 不会。schedule(),进程调度,而schedule_timeout()进行调度之后,一定时间后自动唤醒
        对应于不同的进程状态,使用不同的唤醒函数:
        void wake_up(wait_queue_head_t *queue);
        void wake_up_interruptible(wait_queue_head_t *queue);
        唤醒时很有意思,比如你调用 wake_up 去唤醒一个使用 wait_event 等,进入休眠的进程,唤醒之后,它会判断 condition 是否为真,如果还是假的继续睡眠。至于为什么这个样子,后面分析代码就会明白。
      
      2、手动睡眠
        DECLARE_WAITQUEUE(name, tsk)  创建一个等待队列:
            tsk一般为当前进行current. 这个宏定义并初始化一个名为name的等待队列.
    
     将等待队列头 加入/移除 等待队列:
    
    
            void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
            void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait);
            void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
    

        设置进程状态:

            set_current_state(TASK_INTERRUPTIBLE) 等

        进程调度:  
            schedule() 或者 schedule_timeout()


    三、内核如何实现

        以 wait_event 为例,我们看看内核都干了些什么。

    1. #define wait_event(wq, condition)                   \  
    2. do {                                    \  
    3.     if (condition)                          \  
    4.         break;                          \  
    5.     __wait_event(wq, condition);                    \  
    6. while (0)  
    1. #define __wait_event(wq, condition)                     \  
    2. do {                                    \  
    3.     DEFINE_WAIT(__wait);                        \  
    4.                                     \  
    5.     for (;;) {                          \  
    6.         prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);    \  
    7.         if (condition)                      \  
    8.             break;                      \  
    9.         schedule();                     \  
    10.     }                               \  
    11.     finish_wait(&wq, &__wait);                  \  
    12. while (0)  
    1. #define DEFINE_WAIT(name)                       \  
    2.     wait_queue_t name = {                       \  
    3.         .private    = current,              \  
    4.         .func       = autoremove_wake_function,     \  
    5.         .task_list  = LIST_HEAD_INIT((name).task_list), \  
    6.     }  
    1. typedef struct __wait_queue wait_queue_t;     
    2. struct __wait_queue {  
    3.     unsigned int flags;  
    4. #define WQ_FLAG_EXCLUSIVE   0x01  
    5.     void *private;  
    6.     wait_queue_func_t func;  
    7.     struct list_head task_list;  
    8. };  
    举个例子:宏展开之后
    1. __wait_event(wq, condition);  
    2. wait_queue_t __wait = {                     \  
    3.         .private    = current,              \  
    4.         .func       = autoremove_wake_function,     \  
    5.         .task_list  = LIST_HEAD_INIT((__wait).task_list),   \  
    6.     }  
    7.     for (;;) {                          \  
    8.         prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);    \  
    9.         if (condition)                      \  
    10.             break;                      \  
    11.         schedule();                     \  
    12.     }                               \  
    13.     finish_wait(&wq, &__wait);  
        其实,它定义了一个叫 __wait 的等待队列,private 指向当前进程的 task_struct 结构体(唤醒的时候好知道是哪个进程),然后调用 prepare_to_wait 将等待队列头加入到等待队列中去,并设置当前进程的状态为TASK_UNINTERRUPTIBLE。然后,如果 condition 为假,则schedule(),进程调度的时候,当前进程的状态不是 TASK_RUNNING 必然要被移除 “运行队列”,也就永远不会被调度除非直到醒来。如果 condition 为真,那么finish_wait 会把之前的工作都还原,你继续执行吧,你要的条件都满足了,你还休眠个屁!

        涉及的函数代码贴一贴

    1. void fastcall  
    2. prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)  
    3. {  
    4.     unsigned long flags;  
    5.   
    6.     wait->flags &= ~WQ_FLAG_EXCLUSIVE;  
    7.     spin_lock_irqsave(&q->lock, flags);  
    8.     if (list_empty(&wait->task_list))  
    9.         __add_wait_queue(q, wait);  
    10.     /* 
    11.      * don't alter the task state if this is just going to 
    12.      * queue an async wait queue callback 
    13.      */  
    14.     if (is_sync_wait(wait))  
    15.         set_current_state(state);  
    16.     spin_unlock_irqrestore(&q->lock, flags);  
    17. }  
    1. void fastcall finish_wait(wait_queue_head_t *q, wait_queue_t *wait)  
    2. {  
    3.     unsigned long flags;  
    4.   
    5.     __set_current_state(TASK_RUNNING);  
    6.   
    7.     if (!list_empty_careful(&wait->task_list)) {  
    8.         spin_lock_irqsave(&q->lock, flags);  
    9.         list_del_init(&wait->task_list);  
    10.         spin_unlock_irqrestore(&q->lock, flags);  
    11.     }  
    12. }  
        下面来看看如何唤醒的

    1. #define wake_up(x) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, NULL)  

    1. void fastcall __wake_up(wait_queue_head_t *q, unsigned int mode,  
    2.             int nr_exclusive, void *key)  
    3. {  
    4.     unsigned long flags;  
    5.   
    6.     spin_lock_irqsave(&q->lock, flags);  
    7.     __wake_up_common(q, mode, nr_exclusive, 0, key);  
    8.     spin_unlock_irqrestore(&q->lock, flags);  
    9. }  
    1. static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,  
    2.                  int nr_exclusive, int sync, void *key)  
    3. {  
    4.     struct list_head *tmp, *next;  
    5.   
    6.     list_for_each_safe(tmp, next, &q->task_list) {  
    7.         wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);  
    8.         unsigned flags = curr->flags;  
    9.   
    10.         if (curr->func(curr, mode, sync, key) &&  
    11.                 (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)  
    12.             break;  
    13.     }  
    14. }  
       此时会调用到,我们在等待队列里指定的那个 func 函数,也就是 autoremove_wake_function
    1. int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)  
    2. {  
    3.     int ret = default_wake_function(wait, mode, sync, key);  
    4.   
    5.     if (ret)  
    6.         list_del_init(&wait->task_list);  
    7.     return ret;  
    8. }  
    1. int default_wake_function(wait_queue_t *curr, unsigned mode, int sync,  
    2.               void *key)  
    3. {  
    4.     return try_to_wake_up(curr->private, mode, sync);  
    5. }  
       最终调用到 default_wake_function 来唤醒 等待队列里 private 里指定的那个进程。然后,移除将等待队列头移除等待队列。try_to_wake_up ,会将 要唤醒进程的 进程状态设置为 TASK_RUNNING ,然后放到 “运行队列”中。

    有意思的是:

        我们休眠时,schedule() 在哪里? TMD 居然在 for 循环里

    1. for (;;) {                          \  
    2.     prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);    \  
    3.     if (condition)                      \  
    4.         break;                      \  
    5.     schedule();                     \  
    6. }  
        唤醒之后,那么又开始了 prepare_to_wait ,判断 condition ....显然 condition 为真,才会真正的 唤醒。
        理解了他们,对于手动休眠也就很明白了。手动休眠就不用判断什么 condition 了。
    1. DECLARE_WAITQUEUE(name, tsk)  
    2. tsk一般为当前进行current. 这个宏定义并初始化一个名为name的等待队列.  
    3.   
    4. #define DECLARE_WAITQUEUE(name, tsk)                    \  
    5.     wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)  
    6. #define __WAITQUEUE_INITIALIZER(name, tsk) {                \  
    7.     .private    = tsk,                        \  
    8.     .func        = default_wake_function,            \  
    9.     .task_list    = { NULL, NULL } }  
    10.       
    11. void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);  
    12. void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait);  
    13. void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);  
    14.   
    15. void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)  
    16. {  
    17.     unsigned long flags;  
    18.   
    19.     wait->flags &= ~WQ_FLAG_EXCLUSIVE;  
    20.     spin_lock_irqsave(&q->lock, flags);  
    21.     __add_wait_queue(q, wait);  
    22.     spin_unlock_irqrestore(&q->lock, flags);  
    23. }  
    24.   
    25. set_current_state(TASK_INTERRUPTIBLE);    
    26. schedule();  
       简单明了:

        1、创建等待队列、等待队列头

        2、将等待队列头加入到等待队列中去

        3、设置当前进程的进程状态

        4、进程调度~

    展开全文
  • State  进程在执行过程中会根据环境来改变... 进程处于运行(它是系统的当前进程)或者准备运行状态(它在等待系统将CPU分配给它)。  Waiting  进程等待一个事件或者资源。Linux将等待进程分成两类;可中...
  • 操作系统大纲: 进程和线程知识体系: 1. 进程 在多程序系统中,操作系统调度CPU上的进程以获得最大的利用率,此... 短期调度程序从就绪队列中选择另一个进程并将CPU分配给此进程。 这个过程被称为上下文切换。
  • 进程调度

    2019-10-04 10:58:00
     ·切换cpu的当前任务,从一个进程到另一个进程  ·保存当前线程的资源(寄存器等)  ·加载下一个进程的上下文 2、cpu调度   从就绪队列中挑选一个进程作为下一个运行进程  ·通过调度策略选择进程 调度时机:...
  • 结构体进程描述进程

    2016-06-18 19:40:07
    进程有四大状态,分别为可运行状态,等待状态,暂停状态,僵死状态 1)可运行状态 处于这种状态的进程,要么正在运行、...系统中有一个运行队列(run_queue),用来容纳所有处于可 运行状态的进程,调度程序执行
  • 进程:计算机中已运行的程序,一个进程在运行的过程中可能存在的状态 新生(new):进程新产生中。 运行(running):正在运行。 等待(waiting):等待某事发生,例如等待用户输入完成。亦称“阻塞”(blocked...
  • 进程通讯-Condition

    2020-10-20 22:37:40
    await(): 调用await方法的线程释放当前的lock,当前线程处于等待状态。类似于synchronized的wait()方法。 signal(): 调用signal方法使得当前condition的wait线程处于唤醒状态。 类似于synchronized的notify()方法,...
  • 信号是异步的:一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号什么时候到达。进程之间可以互相通过信号相互交流。内核进程也可以利用它来通知用户空间进程发生了那些系统事件。它可以在任何...
  • 4) 在进程执行过程中,产生随机数0或1,该随机数为1时,将等待队列中的第一个PCB加入就绪队列的对尾; 5) 在进程执行过程中,产生一个随机数,表示执行进程能在处理机上执行的时间,如果随机时间大于总需要的时间...
  • 进程通讯-wait notify

    2020-05-25 23:09:26
    wait():调用wait方法的线程释放当前的锁,并使当前线程处于等待状态。 notify():使用notify方法,使得用notify调用者对象作为Monitor的wait线程随机一个被唤醒。 notifyAll(): 使得用notifyAll()调用者对象作为...
  • 该随机数为2时,将该进程插入等待队列的队尾,同时将等待队列中的第一个进程插入就绪队列的队尾。 5) 一直到就绪队列为空,程序执行结束。 参考书目: 1)计算机操作系统教程 徐甲同 等编 西安电子科技大学出版社 2...
  • Linux五种状态

    2021-05-08 17:17:19
    在Linux系统中,一个进程被创建之后,在系统中可以有下面5种状态。进程的当前状态记录在进程控制块的state成员中。 就绪状态和运行状态 运行状态,顾名思义就是程序进入运行队列,等待运行。 就绪状态状态标志...
  • 一个进程有一个PCB,其内容可以根据具体情况设定。 可以在界面设定的互斥资源(包括两种:输入设备与输出设备)的数目 进程数、进入内存时间、要求服务时间可以在界面上进行设定 进程之间存在一定的同步与互斥...
  • 执行模型:程序在CPU突发和I/O中交替  每个调度决定都是关于在下一个CPU突发时将哪个工作交给CPU;...周转时间:一个进程从初始化到结束,包括所有等待时间所花费的时间 等待时间:进程在就绪队列中的总时间 响...
  • 多任务,多进程,多线程解析

    千次阅读 2011-03-06 11:21:00
    先弄清几个基本概念: 进程和线程都是操作系统中的概念,主要是面向计算机而言的。...每个进程可能处于下列状态:新建,运行,等待,就绪,终止。 线程也可以被看做轻量级进程。在引入了线程的操作系
  • 一个进程发送令牌后等待其返回时也处于阻塞状态。发送令牌带来的开销与上下文切换带来的开销相比,可以忽略不计。 (利用管道传递令牌) 测试程序(1) 使用gettimeofday()获取当前时间 ----------------------...
  • pg_stat_activity 是一张postgresql的系统视图,它的每一行都表示一个系统进程,显示与当前会话的活动进程的一些信息,比如当前回话的状态和查询等。它的state表示当前进程状态,一共有六种: Active(活动): 进程...
  • JAVA 线程状态

    2015-06-29 18:26:00
    也不一定是正在执行代码,也可能是在处于一个等待调度以获取CPU的状态,不过一般这个调度时间非常短暂,对外界来说线程一直是在连续执行的。这个和操作系统里进程调度相关情况一致。yield可以让出线程当前...
  • 日志文件相关等待

    2017-09-18 09:40:59
    log file switch 当日志文件发生切换时出现,在数据库进行日志切换时,后台进程 LGWR需要关闭当前日志组,切换并打开下一个日志组,在这个切换过程中,数据库的所有 DML 操作都处于停顿状态,直至这个切换完成。...
  • 处于挂起状态进程不能接受处理机调度   同步机制遵循的规则: 空闲让进 忙则等待 有限等待 让权等待 记录型信号量的wait和signal wait -- &lt;0 进程加到链表 signal ++ &lt;=0 ...
  • linux 内核研究<> 1.2

    2016-11-04 13:57:01
    进程状态进程描述符中的state域描述了进程的当前五种状态,并且系统中每个进程都必然处于这几种状态种:TASK_RUNNING:进程可执行,或正在运行,或在就绪队列run-queue中准备运行的进程,实际参与进程调度。...
  • PV原子操作组合

    2021-05-27 14:06:02
    P操作:S信号量自减1,如果S小于0,阻塞当前进程状态,放到一个进程队列,此时这个进程就处于一个等待状态;否则继续运行 V操作:S信号量自加1,如果S小于等于0,阻塞当前进程状态,放到一个进程队列,此时这个进程...
  • 选择题 1.引入多道程序的目的在于( A )。 A.充分利用CPU,减少CPU等待...2. 一个进程当前处于等待状态,则( D )。 A. 它可以被调度而获得处理机 B.它可能变成就绪状态,也可能直接获得处理机 C.它永...
  • 理解死锁产生的四必要条件

    千次阅读 2020-07-05 22:25:47
    此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待进程称为死锁进程。 死锁产生的四个必要条件 1、互斥条件:线程对已经获取到的资源进行排他性使用,即该资源同时只有一个线程占用,如果此时还有其他...
  • 阻塞(blocking)和非阻塞(non-blocking):阻塞和非阻塞是指用户进程在做read(), write()等系统调用的时候,根据系统调用当前所处的状态而采取的...非阻塞情况下,如果数据没有到达,则立即返回给用户进程一个状态信息

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 153
精华内容 61
关键字:

一个进程当前处于等待状态