Linux进程管理 (篇外)内核线程简要介绍

关键词:kthread、irq、ksoftirqd、kworker、workqueues

在使用ps查看线程的时候,会有不少[...]名称的线程,这些有别于其它线程,都是内核线程。

其中多数内核线程从名称看,就知道其主要功能。

比如给中断线程化使用的irq内核线程,软中断使用的内核线程ksoftirqd,以及work使用的kworker内核线程。

本文首先概览一下Linux都有哪些内核线程,然后分析创建内核线程的API。

在介绍内核线程和普通线程都有哪些区别?

最后介绍主要内核线程(irq/ksoftirqd/kworker/)的创建过程及其作用。

1. ps下初步认识Linux内核线程

在ps -a会显示如下,可以看出内核线程都用[...]标注。

并且pid=1的init进程是所有用户空间进程的父进程;pid=2的kthreadd内核线程是所有内核线程的父线程。

内核线程分为几大类:softirq、kworker、irq及其他。

PID   USER     TIME   COMMAND
    1 0          0:01 {linuxrc} init
    2 0          0:00 [kthreadd]
    3 0          0:00 [ksoftirqd/0]
    4 0          0:00 [kworker/0:0]
    5 0          0:00 [kworker/0:0H]
    6 0          0:00 [kworker/u8:0]
    7 0          0:00 [rcu_sched]
    8 0          0:00 [rcu_bh]
    9 0          0:00 [migration/0]
   10 0          0:00 [migration/1]
   11 0          0:00 [ksoftirqd/1]
   12 0          0:00 [kworker/1:0]
   13 0          0:00 [kworker/1:0H]
   14 0          0:00 [migration/2]
   15 0          0:00 [ksoftirqd/2]
   16 0          0:00 [kworker/2:0]
   17 0          0:00 [kworker/2:0H]
   18 0          0:00 [migration/3]
   19 0          0:00 [ksoftirqd/3]
   20 0          0:00 [kworker/3:0]
   21 0          0:00 [kworker/3:0H]
   22 0          0:00 [khelper]
   23 0          0:00 [kdevtmpfs]
   24 0          0:00 [perf]
   25 0          0:00 [kworker/u8:1]
  279 0          0:00 [khungtaskd]
  280 0          0:00 [writeback]
  281 0          0:00 [kintegrityd]
  282 0          0:00 [kworker/0:1]
  284 0          0:00 [bioset]
  286 0          0:00 [kblockd]
  294 0          0:00 [ata_sff]
  408 0          0:00 [rpciod]
  409 0          0:00 [kworker/2:1]
  410 0          0:00 [kworker/1:1]
  412 0          0:00 [kswapd0]
  416 0          0:00 [fsnotify_mark]
  429 0          0:00 [nfsiod]
  449 0          0:00 [kworker/3:1]
  527 0          0:00 [kpsmoused]
  537 0          0:00 [kworker/1:2]
  613 0          0:00 [deferwq]

2. kthreadd以及创建内核线程API

2.1 kthreadd:kthreadd内核线程的创建

内核其他线程的创立,要基于kthreadd。kthreadd线程是其他线程的父线程。

start_kernel-->rest_init如下:

static noinline void __init_refok rest_init(void)
{
    int pid;

    rcu_scheduler_starting();
    /*
     * We need to spawn init first so that it obtains pid 1, however
     * the init task will end up wanting to create kthreads, which, if
     * we schedule it before we create kthreadd, will OOPS.
     */
    kernel_thread(kernel_init, NULL, CLONE_FS);--------------------------------创建第一个用户空间线程init
    numa_default_policy();
    pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);---------------创建第一个内核线程kthreadd
    rcu_read_lock();
    kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);--------------------kthreadd_task指向kthreadd的task_strcut结构体
    rcu_read_unlock();
    complete(&kthreadd_done);--------------------------------------------------在init进程kernel_init-->kernel_init_freeable中等待kthreadd_done释放

    /*
     * The boot idle thread must execute schedule()
     * at least once to get things moving:
     */
    init_idle_bootup_task(current);
    schedule_preempt_disabled();
    /* Call into cpu_idle with preempt disabled */
    cpu_startup_entry(CPUHP_ONLINE);
}

kernel_init在kthreadd之前启动,但是kernel_init的很多任务需要基于kthreadd。所以在kernel_init的开头等待reset_init的kthreadd_done完成量。

因为kernel_init-->kernel_init_freeable-->do_basic_setup-->do_initcalls中很多初始化需要kthread_create支援。

kernel_init-->kernel_init_freeable:
static noinline void __init kernel_init_freeable(void)
{
    /*
     * Wait until kthreadd is all set-up.
     */
    wait_for_completion(&kthreadd_done);-------------------等待kthreadd_done完成量
...

do_basic_setup();---------------------------------------很多初始化需要kthread_create支持

...
}

内核中有一个线程kthreadd_task负责创建其他内核线程,这个线程的函数为kthreadd()。

int kthreadd(void *unused)
{
    struct task_struct *tsk = current;

    /* Setup a clean context for our children to inherit. */
    set_task_comm(tsk, "kthreadd");
    ignore_signals(tsk);
    set_cpus_allowed_ptr(tsk, cpu_all_mask);
    set_mems_allowed(node_states[N_MEMORY]);

    current->flags |= PF_NOFREEZE;

    for (;;) {
        set_current_state(TASK_INTERRUPTIBLE);
        if (list_empty(&kthread_create_list))
            schedule();----------------------------------------------如果kthread_create_list为空,让出CPU,进入休眠状态。在kthread_create_on_node()中会将要创建进程节点加入到kthread_create_list中,然后唤醒此进程。
        __set_current_state(TASK_RUNNING);

        spin_lock(&kthread_create_lock);
        while (!list_empty(&kthread_create_list)) {------------------只要kthread_create_list不为空,遍历kthread_create_list链表
            struct kthread_create_info *create;

            create = list_entry(kthread_create_list.next,
                        struct kthread_create_info, list);
            list_del_init(&create->list);----------------------------从kthread_create_list中摘除当前create
            spin_unlock(&kthread_create_lock);

            create_kthread(create);----------------------------------创建线程

            spin_lock(&kthread_create_lock);
        }
        spin_unlock(&kthread_create_lock);
    }

    return 0;
}

static void create_kthread(struct kthread_create_info *create)
{
    int pid;

#ifdef CONFIG_NUMA
    current->pref_node_fork = create->node;
#endif
    /* We want our own signal handler (we take no signals by default). */
    pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);----调用do_fork()创建线程
    if (pid < 0) {
        /* If user was SIGKILLed, I release the structure. */
        struct completion *done = xchg(&create->done, NULL);

        if (!done) {
            kfree(create);
            return;
        }
        create->result = ERR_PTR(pid);
        complete(done);--------------------------------------------------------触发complete事件
    }
}

pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
    return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
        (unsigned long)arg, NULL, NULL);
}

2.2 创建内核线程接口:kthread_create等

kthread_create()是最常见的创建内核线程的接口。

kthread_create_on_cpu()相对于kthread_create多了个cpu,但都基于kthread_create_on_node()。

kthread_run基于kthreadd_create,所以这些函数都基于kthread_create_on_node。

#define kthread_create(threadfn, data, namefmt, arg...) \kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)

struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
                      void *data,
                      unsigned int cpu,
                      const char *namefmt);

/**
 * kthread_run - create and wake a thread.
 * @threadfn: the function to run until signal_pending(current).
 * @data: data ptr for @threadfn.
 * @namefmt: printf-style name for the thread.
 *
 * Description: Convenient wrapper for kthread_create() followed by
 * wake_up_process().  Returns the kthread or ERR_PTR(-ENOMEM).
 */
#define kthread_run(threadfn, data, namefmt, ...)               \
({                                           struct task_struct *__k                                   =kthread_create(threadfn, data, namefmt, ## __VA_ARGS__);     if (!IS_ERR(__k))                           \--------------------------如果kthread_create()正确创建了一个进程,调用wake_up_process()唤醒它。
        wake_up_process(__k);                           __k;                                   })

kthread_create_on_node()负责创建一个线程,填充一个kthread_create_info结构体;然后将此结构体作为一个节点插入kthread_create_list队尾。

然后唤醒kthreadd_task进行处理,创建线程。

struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
                       void *data, int node,
                       const char namefmt[],
                       ...)
{
    DECLARE_COMPLETION_ONSTACK(done);
    struct task_struct *task;
    struct kthread_create_info *create = kmalloc(sizeof(*create),
                             GFP_KERNEL);---------------------------------创建插入kthread_create_list的节点。

    if (!create)
        return ERR_PTR(-ENOMEM);
    create->threadfn = threadfn;
    create->data = data;
    create->node = node;
    create->done = &done;

    spin_lock(&kthread_create_lock);
    list_add_tail(&create->list, &kthread_create_list);-------------------将填充的节点插入kthread_create_list中。
    spin_unlock(&kthread_create_lock);

    wake_up_process(kthreadd_task);---------------------------------------唤醒kthread_task处理kthread_create_list链表,创建相应的线程。
    /*
     * Wait for completion in killable state, for I might be chosen by
     * the OOM killer while kthreadd is trying to allocate memory for
     * new kernel thread.
     */
    if (unlikely(wait_for_completion_killable(&done))) {------------------等待complete事件触发,在create_kthread()中触发。
        /*
         * If I was SIGKILLed before kthreadd (or new kernel thread)
         * calls complete(), leave the cleanup of this structure to
         * that thread.
         */
        if (xchg(&create->done, NULL))
            return ERR_PTR(-EINTR);
        /*
         * kthreadd (or new kernel thread) will call complete()
         * shortly.
         */
        wait_for_completion(&done);---------------------------------------等待complete事件触发。
    }
    task = create->result;------------------------------------------------创建的结果为task_struct结构体。
    if (!IS_ERR(task)) {
        static const struct sched_param param = { .sched_priority = 0 };
        va_list args;

        va_start(args, namefmt);
        vsnprintf(task->comm, sizeof(task->comm), namefmt, args);---------配置进程名称。
        va_end(args);
        /*
         * root may have changed our (kthreadd‘s) priority or CPU mask.
         * The kernel thread should not inherit these properties.
         */
        sched_setscheduler_nocheck(task, SCHED_NORMAL, &param);-----------设置进程调度策略为NORMAL,优先级为0。
        set_cpus_allowed_ptr(task, cpu_all_mask);
    }
    kfree(create);--------------------------------------------------------释放kthread_create_info。
    return task;
}

3. 内核线程和普通线程的区别

内核线程没有地址空间,所以task_struct->mm指针为NULL。内核线程没有用户上下文。

内核线程只工作在内核空间,不会切换至用户空间。但内核线程同样是可调度且可抢占的。

普通线程即可工作在内核空间,也可工作在用户空间。

内核线程只能访问3GB以上地址,而普通线程可访问所有4GB地址空间。

4. irq、softirq、woker内核线程

irq、softirq、worker都可能创建对应的内核线程,有线程就有优先级。

下面从优先来来看看它们的重要性。

可以看出中断内核线程优先级很高,为49,并且使用了实时调度策略。softirq和worker都是普通内核线程。

  prio policy
irq 49 SCHED_FIFO
softirq 120 SCHED_NORMAL
worker 120 SCHED_NORMAL
init 120 SCHED_NORMAL
kthreadd 120 SCHED_NORMAL
cfinteractive 0 SCHED_FIFO

其它特殊内核线程init优先级为120,kthreadd优先级为120.

cfinteractive优先级最高,主要处理CPU Frequency负载更新。

4.1 irq/xx-xx:创建处理线程化中断的线程

request_threaded_irq-->__setup_irq,可见如果设置了thread_fn,并且不允许中断嵌套,则创建一个类似"irq/中断号-终端名称"的线程。

线程函数是irq_thread,

/*
 * Internal function to register an irqaction - typically used to
 * allocate special interrupts that are part of the architecture.
 */
static int
__setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
{
...
    if (new->thread_fn && !nested) {
        struct task_struct *t;
        static const struct sched_param param = {
            .sched_priority = MAX_USER_RT_PRIO/2,
        };

        t = kthread_create(irq_thread, new, "irq/%d-%s", irq,----------------在irq_thread中调用irq_thread_fn,进而调用action->thread_fn,request_threaded_irq参数thread_fn。
                   new->name);
...
    }
...
}

request_irq是对request_threaded_irq的封装,创建中断线程的工作交给__setup_irq()

static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
        const char *name, void *dev)
{
    return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}

更详细信息参考:《Linux中断管理 (1)Linux中断管理机制》中关于request_irq()介绍。

4.2 ksoftirqd/xx:创建处理软中断线程

软中断线程通过smpboot_register_percpu_thread注册softirq_threads创建。

static struct smp_hotplug_thread softirq_threads = {
    .store            = &ksoftirqd,
    .thread_should_run    = ksoftirqd_should_run,
    .thread_fn        = run_ksoftirqd,
    .thread_comm        = "ksoftirqd/%u",
};

static __init int spawn_ksoftirqd(void)
{
    register_cpu_notifier(&cpu_nfb);

    BUG_ON(smpboot_register_percpu_thread(&softirq_threads));

    return 0;
}

smpboot_register_percpu_thread-->__smpboot_create_thread,最终也还是调用kthread_create_on_cpu,创建了类似"ksoftirqd/xx"的内核线程,xx为cpuid号。

从ps -a中可以看出创建的结果如下,可以看出每个CPU创建了一个ksoftirqd内核线程。

    3 0          0:03 [ksoftirqd/0]
   11 0          0:03 [ksoftirqd/1]
   15 0          0:00 [ksoftirqd/2]
   19 0          0:00 [ksoftirqd/3]

更详细信息参考:  《Linux中断管理 (2)软中断和tasklet

4.3 kworker:创建work的工作线程

kwoker线程是处理work的工作线程,详细参考《Linux中断管理 (3)workqueue工作队列》。

每个CPU都会创建自己的workqueue,用以集中处理内核kworker。

workquuue就是把一些任务(work)推迟到一个或一组内核线程中去执行,那个内核线程被称为worker_thread。

首先看看创建结果,可以看出在init_workqueues中创建了绑定CPU0的两个kworker,分别是nice=0和nice=-20。

apply_workqueue_attrs创建unbund worker,即kworker/u8:0。

然后在每个CPU_UP_PREPARE回调中创建两个不同nice的kworker。所以四个CPU一共9个内核线程。

PID   USER     TIME   COMMAND
    1 0          0:01 {linuxrc} init
    2 0          0:00 [kthreadd]
    3 0          0:00 [ksoftirqd/0]
    4 0          0:00 [kworker/0:0]
    5 0          0:00 [kworker/0:0H]---------------init_workqueues-->create_worker
    6 0          0:00 [kworker/u8:0]---------------apply_workqueue_attrs-->alloc_unbound_pwq-->create_worker
    7 0          0:00 [rcu_sched]
    8 0          0:00 [rcu_bh]
    9 0          0:00 [migration/0]
   10 0          0:00 [migration/1]
   11 0          0:00 [ksoftirqd/1]
   12 0          0:00 [kworker/1:0]---------------workqueue_cpu_up_callback-->create_worker
   13 0          0:00 [kworker/1:0H]
   14 0          0:00 [migration/2]
   15 0          0:00 [ksoftirqd/2]
   16 0          0:00 [kworker/2:0]
   17 0          0:00 [kworker/2:0H]--------------workqueue_cpu_up_callback-->create_worker
   18 0          0:00 [migration/3]
   19 0          0:00 [ksoftirqd/3]
   20 0          0:00 [kworker/3:0]
   21 0          0:00 [kworker/3:0H]--------------workqueue_cpu_up_callback-->create_worker
   22 0          0:00 [khelper]
   23 0          0:00 [kdevtmpfs]
   24 0          0:00 [perf]
   25 0          0:00 [kworker/u8:1]--------------worker_thread-->create_worker
  279 0          0:00 [khungtaskd]
  280 0          0:00 [writeback]
  281 0          0:00 [kintegrityd]
  282 0          0:00 [kworker/0:1]---------------worker_thread-->create_worker
  284 0          0:00 [bioset]
  286 0          0:00 [kblockd]
  294 0          0:00 [ata_sff]
  408 0          0:00 [rpciod]
  409 0          0:00 [kworker/2:1]---------------worker_thread-->create_worker
  410 0          0:00 [kworker/1:1]---------------worker_thread-->create_worker
  412 0          0:00 [kswapd0]
  416 0          0:00 [fsnotify_mark]
  429 0          0:00 [nfsiod]
  449 0          0:00 [kworker/3:1]---------------worker_thread-->create_worker
  527 0          0:00 [kpsmoused]
  537 0          0:00 [kworker/1:2]---------------worker_thread-->create_worker
  613 0          0:00 [deferwq]

init_workqueues-->create_worker-->kthread_create_on_node,创建"kworker/xx:xxH"内核线程。

static int __init init_workqueues(void)
{
    int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL };
    int i, cpu;
...
    /* create the initial worker */
    for_each_online_cpu(cpu) {---------------------------------遍历CPU[0~3]
        struct worker_pool *pool;

        for_each_cpu_worker_pool(pool, cpu) {------------------NR_STD_WORKER_POOLS=2,所以每个CPU有两个pool
            pool->flags &= ~POOL_DISASSOCIATED;
            BUG_ON(!create_worker(pool));
        }
    }
...
    system_wq = alloc_workqueue("events", 0, 0);
    system_highpri_wq = alloc_workqueue("events_highpri", WQ_HIGHPRI, 0);
    system_long_wq = alloc_workqueue("events_long", 0, 0);
    system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND,
                        WQ_UNBOUND_MAX_ACTIVE);
    system_freezable_wq = alloc_workqueue("events_freezable",
                          WQ_FREEZABLE, 0);
    system_power_efficient_wq = alloc_workqueue("events_power_efficient",
                          WQ_POWER_EFFICIENT, 0);
    system_freezable_power_efficient_wq = alloc_workqueue("events_freezable_power_efficient",
                          WQ_FREEZABLE | WQ_POWER_EFFICIENT,
                          0);
    BUG_ON(!system_wq || !system_highpri_wq || !system_long_wq ||
           !system_unbound_wq || !system_freezable_wq ||
           !system_power_efficient_wq ||
           !system_freezable_power_efficient_wq);
    return 0;
}

create_worker()函数创建工作线程。

static struct worker *create_worker(struct worker_pool *pool)
{
...
    if (pool->cpu >= 0)
        snprintf(id_buf, sizeof(id_buf), "%d:%d%s", pool->cpu, id,-------------cpuid和id,区分cpu和cpu内kworker。
             pool->attrs->nice < 0  ? "H" : "");
    else
        snprintf(id_buf, sizeof(id_buf), "u%d:%d", pool->id, id);--------------u表示不指定cpu。

    worker->task = kthread_create_on_node(worker_thread, worker, pool->node,
                          "kworker/%s", id_buf);
...
}

更详细信息参考:《Linux中断管理 (3)workqueue工作队列》、《Linux workqueue工作原理》、《Concurrency Managed Workqueue之(一):workqueue的基本概念

5. 其他内核线程

rcu_sched、rcu_bh

migration

khelper

kdevtmpfs

perf

writeback

kintegrityd

bioset

kblockd

ata_sff

rpciod

kswapd

nfsiod

kpsmpused

deferwq

原文地址:https://www.cnblogs.com/arnoldlu/p/8336998.html

时间: 2024-10-13 10:05:42

Linux进程管理 (篇外)内核线程简要介绍的相关文章

Linux进程管理优化及性能评估工具介绍

衡量Linux CPU使用的指标 需要关注以下地方: 第一段需要关注的值: ·使用率 ·在用户空间所消耗的时间百分比 ·在系统空间锁消耗的时间百分比 ·消耗在IO等待上的时间 如果一个主机上有大量的cpu消耗在IO等待上,那么说明IO活动非常频繁,而IO子系统性能非常差. 因此我们看到wite的时间居高不下时,说明IO活动非常频繁的,IO子系统非常差 但如果wite的时间不是特别离谱,一般而言问题都不大 第二段需要关注的值: ·空闲时间 ·平均负载,CPU等待运行活动队列中等待运行的进程的个数

Linux进程管理与调度-之-目录导航【转】

转自:http://blog.csdn.net/gatieme/article/details/51456569 版权声明:本文为博主原创文章 && 转载请著名出处 @ http://blog.csdn.net/gatieme 目录(?)[-] 项目链接 进程的描述 进程的创建 进程的加载与运行 进程的退出 进程的调度 调度普通进程-完全公平调度器CFS 日期 内核版本 架构 作者 GitHub CSDN 2016-07-21 Linux-4.6 X86 & arm gatieme

Linux性能及调优指南(翻译)之Linux进程管理

译文如下:1.1 Linux进程管理 进程管理是操作系统的最重要的功能之一.有效率的进程管理能保证一个程序平稳而高效地运行. Linux的进程管理与UNIX的进程管理相似.它包括进程调度.中断处理.信号.进程优先级.上下文切换.进程状态.进度内存等. 在本节中,我们将描述Linux进程管理的基本原理的实现.它将更好地帮助你理解Linux内核如何处理进程及其对系统性能的影响. 1.1.1 什么是进程?一个进程是一个运行在处理器的程序的一个实例.该进程使用Linux内核能够处理的任何资源来完成它的任

Linux进程管理知识整理

Linux进程管理知识整理 1.进程有哪些状态?什么是进程的可中断等待状态?进程退出后为什么要等待调度器删除其task_struct结构?进程的退出状态有哪些? TASK_RUNNING(可运行状态) TASK_INTERRUPTIBLE(可中断等待状态) TASK_UNINTERRUPTIBLE(不可中断等待状态) TASK_STOPPED(进程被其它进程设置为暂停状态) TASK_TRACED(进程被调试器设置为暂停状态) TASK_DEAD(退出状态) 进程由于所需资源得不到满足,从而进入

linux进程管理相关概念

我们知道,不管是在繁忙的服务器还是比较空闲的pc机上,系统都不只是运行一个进程,在linux上,当用户输入命令,在程序被载入内存执行之后我们称之为进程. 计算机的核心组件,cpu和内存,cpu由运算器和控制器组成,cpu只能从内存读入数据进行计算,那么在linux系统上,当用户输入一个命令,这条命令所对应的程序代码就会被装载进内存,然后由cpu执行,正是因为同时有多个进程需要执行而cpu只有一颗的情况下,在众多进程之间完成切换就显得比较重要. 我们知道,cpu提供的计算能力是按照时间的流逝来计算

linux进程管理命令

进程管理类的命令: pstree,ps,top,vmstat,htop,pmap pstree:查看进程树 ps:显示系统当前进程状态的命令 进程: 跟终端相关的进程 跟终端无关的进程 a:所有跟终端相关的进程 ps a x:所有跟终端无关的进程 ps x STAT: S:可中断睡眠 D:不可中断睡眠 R:运行或可运行 T:停止 Z:僵死 s:session leader l:多线程进程 +:前台进程: N:低优先级进程 <:高优先级进程 COMMAND:由哪个命令发起的进程 []:内核线程 u

《Linux性能及调优指南》----1.1 Linux进程管理

翻译:飞哥 ( http://hi.baidu.com/imlidapeng ) 版权所有,尊重他人劳动成果,转载时请注明作者和原始出处及本声明. 原文名称:<Linux Performance and Tuning Guidelines> 原文地址:http://www.redbooks.ibm.com/abstracts/redp4285.html -----------------------------------------------------------------------

Linux进程管理 (7)实时调度

关键词:RT.preempt_count.RT patch. 除了CFS调度器之外,还包括重要的实时调度器,有两种RR和FIFO调度策略.本章只是一个简单的介绍. 更详细的介绍参考<Linux进程管理 (9)实时调度类分析,以及FIFO和RR对比实验>. 同时为了提高Linux的实时性,Linux社区还维护了realtime相关的补丁.这些补丁的介绍在<Linux实时补丁及其分析>. 1. 抢占内核 如果Linux内核不支持抢占,那么进程要么主动要求调度,如schedule()或者

Linux进程管理.md

目录 Linux进程管理 1.进程基本概述 1.1.进程的组成部分 1.2.进程的环境 1.3.进程的产生 1.4.进程的分类 2.进程状态 2.1.Linux进程状态 3.2.进程优先级 3.3.相对优先级 3.4.nice级别与权限 3.5.进程优先级调整 4.进程管理命令 4.1.ps 4.2.pstree 4.3.pgrep 4.4.pidof 4.5.vmstat 5.控制作业 5.1.作业与会话 5.2.作业分类 5.3.在后台运行作业 6.进程间通信 7.使用信号控制进程 8.监控