Article count:948 Read by:3148873

Featured Content
Account Entry

Explain in detail why the process needs to sleep?

Latest update time:2024-11-18
    Reads:


Link: https://www.cnblogs.com/ydswin/p/18079436

A process is a part of the operating system 执行上下文 . To put it simply, 执行上下文 it includes the code to be executed and its related resources. The code to be executed is relatively easy to understand, which is the program code we write, for example:

int total = 10 + 20;

The code above assigns the result of adding 10 and 20 to total the variable , which is the code that the process will execute.

The resources related to the process include: 使用的内存 , 打开的文件 , 使用的CPU时间 and so on. The executed code and its related resources constitute 执行上下文 , also called 进程 . If people are compared to processes, then our daily behavior corresponds to the execution code, and the various social resources we have (such as money, real estate, cars, etc.) correspond to the resources occupied by the process.

Why do processes need to sleep?

Since the CPU is the main body of code execution, the code of the process needs to occupy CPU time. But sometimes the execution of the process requires some resources to provide data sources, and these resources may need to be obtained from the outside. For example, in a network program, the server needs to wait for the client to make a request before proceeding to the next step. But it is uncertain when the server will receive the client's request, and it may not receive the client's request for a whole day.

The server program can wait for the client's request in two ways: 忙等待 and 睡眠与通知 .

1. Busy Waiting

忙等待 It means to continuously detect whether the data is ready through an infinite loop, as shown in the following pseudo code:

for (;;) {
    if (如果数据准备好) {
        读取数据;
        break;
    }
}

As can be seen from the above code, busy waiting consumes a lot of CPU time to detect whether the data is ready.

Let's take an example from daily life 忙等待 . For example, when we eat out, when the restaurant is very busy, we may need to wait for a table. While waiting, we need to keep asking the waiter to understand the status of the vacant seats.

2. Sleep and wake-up

It can be seen that busy waiting is a very inefficient and time-wasting way. So is there a more efficient way? The answer is yes.

Let's take waiting for a table in a restaurant as an example. If the restaurant provides a device to notify guests, the waiter can use this device to notify the waiting guests when there is a vacancy. Then, the guests do not need to constantly ask the waiter about the vacancy status, and can take a nap while waiting.

Similarly, while the server program is waiting for a client request to arrive, the operating system can suspend the server process (sleep) and then execute other executable processes. When a client request arrives, the operating system wakes up the server process to handle the client request.

As shown in the following figure:

When 进程M is waiting for some resources in the system to become ready, the operating system will 进程M switch out of the CPU and put 进程M into the sleep queue. Then the operating system will select the most suitable process (as shown in the figure 进程1 ) from the runnable queue and schedule it to the CPU to run.

When 进程M the waiting resource becomes ready, the operating system will put 进程M it back into the runnable queue. In this way, 进程M it can compete for the CPU's running time in the next scheduling cycle. As shown in the following figure:

In the above figure, when a client request arrives, the operating system wakes up the waiting client request 进程M and puts it back into the runnable queue.

This is the sleep and wake-up mechanism in the operating system.

Implementation of sleep and wake-up mechanism of Linux

In the Linux kernel, many system calls and kernel functions may cause a process to sleep, such as I/O-related system calls, sleep kernel-like functions, memory allocation functions, etc.

Next, we will use sleep the kernel functions of the class to analyze how Linux implements the sleep and wake-up mechanism.

1. Use of sleep function

In the Linux kernel, if you want to put a process into sleep mode, you can call schedule_timeout_interruptible() the kernel function. Its prototype is as follows:

signed long __sched schedule_timeout_interruptible(signed long timeout);

Parameters timeout indicate how long you want the process to sleep. This function will make the process sleep timeout for ticks. For example, if you want the process to sleep for 1 second, you can use the following code to achieve it:

...
schedule_timeout_interruptible(1 * HZ);
// 1秒后进程被唤醒,继续执行下面代码
...

2. Implementation of sleep function

Next, let's analyze schedule_timeout_interruptible() how the kernel function puts the process into sleep mode. The code is as follows:

signed long __sched schedule_timeout_interruptible(signed long timeout)
{
    __set_current_state(TASK_INTERRUPTIBLE);
    return schedule_timeout(timeout);
}

schedule_timeout_interruptible() The kernel function mainly does the following two things:

  • Call __set_current_state() the function to set the process to be interruptible 中断睡眠状态 . It should be noted that this step only sets the state of the process to an interruptible sleep state, but the process has not yet been removed from the CPU by the kernel scheduler.
  • Calling schedule_timeout() the function makes the process actually enter the sleep state (give up the right to use the CPU).

From the above code, we can see that schedule_timeout() the function is the main body that puts the process to sleep. Then, let's continue to analyze schedule_timeout() the implementation of the function:

signed long __sched schedule_timeout(signed long timeout)
{
    struct timer_list timer;
    unsigned long expire;

    ...
    expire = timeout + jiffies;

    // 1. 将当前进程添加到定时器中,定时器的超时时间为expire,回调函数为process_timeout
    setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
    __mod_timer(&timer, expire, false, TIMER_NOT_PINNED);

    // 2. 主动触发内核进行进程调度
    schedule();

    // 3. 将进程从定时器中删除
    del_singleshot_timer_sync(&timer);
    destroy_timer_on_stack(&timer);

    timeout = expire - jiffies;

 out:
    return timeout < 0 ? 0 : timeout;
}

schedule_timeout() The logic of the function is mainly divided into the following three steps:

  • Add the current process to the timer, set the timeout of the timer to expire , and the callback function to process_timeout() . Then when the timer times out, it will trigger the call of process_timeout() the function.
  • Calling schedule() the function triggers the kernel to schedule the process. Since the current process schedule_timeout_interruptible() is set to in the function 可中断睡眠状态 , when the scheduler finds that the current process is 可中断睡眠状态 , it will remove the current process from the runnable queue and give up the right to use the CPU.
  • When the process is awakened, it will be deleted from the timer.

From the above analysis, we can see that when calling schedule_timeout() the function, the kernel will create a timer for the current process, and its timeout period is set to schedule_timeout() the parameter passed by the function plus the current time. When the timer expires, it will trigger the call of process_timeout() the function, and process_timeout() the function will eventually call try_to_wake_up() the function to wake up the process.

Let's analyze try_to_wake_up() the implementation of the function and see how it wakes up the process:

static int
try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
{
    unsigned long flags;
    int cpu, success = 0;

    ...
    // 1. 为进程挑选一个最合适的 CPU 运行
    cpu = select_task_rq(p, p->wake_cpu, SD_BALANCE_WAKE, wake_flags);
    ...
    // 2. 把进程添加到 CPU 的可运行队列中
    ttwu_queue(p, cpu);
    ...
    return success;
}

In the above code, we only keep the core code. It can be seen that try_to_wake_up() the function mainly completes 2 things:

  • Call select_task_rq() the function to select the most suitable CPU for the process to run.
  • Calling ttwu_queue() the function adds the process to the CPU's runnable queue.

After the awakened process is added to the CPU's runnable queue, it will not be executed immediately. The kernel will select a suitable process for scheduling in the next scheduling cycle, and the awakened process may be selected to run.

Summarize

This article mainly introduces why processes need to have sleep and wake-up functions, and analyzes the implementation principles of process sleep and wake-up. The process sleep and wake-up functions are mainly to solve the problem that processes need to constantly detect the status of resources when waiting for certain resources to become available. This detection not only wastes precious CPU time, but also affects the system throughput.

Process sleep can actively give up the right to use the CPU when the process is waiting for resources to become available, so that the CPU can run other executable processes, thereby achieving optimal CPU utilization. When the resources that the process is waiting for become available, the kernel actively wakes up the waiting process and the process can continue to run.



Autumn The recruitment has already begun. If you are not well prepared, Autumn It's hard to find a good job.


Here is a big employment gift package for everyone. You can prepare for the spring recruitment and find a good job!



Latest articles about

 
EEWorld WeChat Subscription

 
EEWorld WeChat Service Number

 
AutoDevelopers

About Us Customer Service Contact Information Datasheet Sitemap LatestNews

Room 1530, Zhongguancun MOOC Times Building,Block B, 18 Zhongguancun Street, Haidian District,Beijing, China Tel:(010)82350740 Postcode:100190

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号