[LINUX-04]linux进程、调度、线程、进程上下文等几点理解

摘要:
调用pthread_create函数的线程和新线程的执行顺序是随机的。3.在Linux中,与线程操作相关的功能通过第三方线程库(Linux线程或NativePOSIXThreadLibrary(NPTL))实现。4.down()/down_cruptible()用于同步内核空间中的执行单元。sleep函数可用于释放线程的cpu控制。测试代码是#include<

1、信号来自进程或内核
2、线程共享进程的代码空间和数据空间(全局变量或静态变量),文件描述符,信号,以及malloc分配的内存,每个线程拥有独立的栈空间和程序计数器,在创建线程时,调用pthread_create函数的线程和新建线程的执行顺序随机

3、在linux中,使用轻量级进程来模拟线程,线程操作的相关函数通过第三方线程库 (Linuxthreads 或 Native POSIX Thread Library(NPTL))来实现

4、down()/down_interruptible()用于内核空间执行单元的同步,其中down(struct semaphore *sem)用于获取信号量sem,如果调用者获取不到信号量,将会导致睡眠,进入睡眠状态的进程不能被信号打断,而因down_interruptible进入睡眠状态的进程能被信号打断,导致该函数返回。

5、时间片:进程处于运行状态时所剩余的时钟滴答数 ,每次时钟中断到来时,这个 值就减1。当这个域的值变得越来越小,直至为0 时,就把need_resched 域置1(在调度时机到来时,检测这个域的值,如果为1,则调用schedule())

6、OS时钟(嘀嗒时钟)作为linux系统调度的基准时钟。

7、linux多线程编程中,可使用sleep函数来释放线程的cpu控制权,测试代码如下

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>


void *SleepTest1(void *arg)
{
        while(1)
        {
                printf("the sleeptest1 is ok!
");
                sleep(3);
        }
}


void *SleepTest2(void *arg)
{
        while(1)
        {
                printf("the sleeptest2 is ok!
");
                sleep(10);
        }
}

int main(int argc, char *argv[])
{
        pthread_t tid[2];
        int ret;
        ret = pthread_create(&tid[0], NULL, SleepTest1, NULL);
        if(ret < 0)
        {
                printf("pthread_create");
                return -1;
        }
        ret = pthread_create(&tid[1], NULL, SleepTest2, NULL);
        if(ret < 0)
        {
                perror("pthread_create");
                return -1;
        }
        printf("the thread1 and thread2 create ok!
");

        pthread_join(tid[0],NULL);
        pthread_join(tid[1],NULL);
        printf("the thread exit!
");

        return 0;
}

8、僵死进程:在每个进程退出的时候,内核释放该进程所有的资源(包括打开的文件、占用的内存等),但是仍然为其保留一定的信息(包括进程号,退出状态,运行时间等),直到父进程通过外wait/waitpid来取时才释放。此时该进程处于僵死状态。

9、进程退出

进程在退出时,必须释放它所拥有的资源,并通过某种方式(发送SIGCHLD信号)告诉父进程。进程的退出一般是显示或隐式地调用了eixt(),或者接受了某种信号。不过什么原因退出,最终都调用了do_exit。

用于进程退出的系统调用有两个exit和exit_group,exit只是终止某个进程,而exit_group整个线程中的进程。它们在内核中的服务函数分别为sys_exit和sys_exit_group,它们又分别调用了do_exit和do_group_exit。而do_group最终又调用了do_exit(do_exit定义在kernel/exit.c中)。

10、查看某进程打开的文件描述符

[root@localhost proc]# cd 1328/
[root@localhost 1328]# ls
attr    clear_refs       cpuset   exe     io       loginuid  mountinfo   net        pagemap      sched      smaps  statm    task
auxv    cmdline          cwd      fd      latency  maps      mounts      oom_adj    personality  schedstat  stack  status   wchan
cgroup  coredump_filter  environ  fdinfo  limits   mem       mountstats  oom_score  root         sessionid  stat   syscall
[root@localhost 1328]# cd fdinfo/
[root@localhost fdinfo]# ls
0  1  10  11  12  13  14  15  16  17  18  19  2  20  21  22  23  3  4  5  6  7  8  9
[root@localhost fdinfo]# 

fdinfo文件夹中列出的数字,即该进程打开的文件描述符

11、fork函数

fork在复制的时候,parent顺序执行过的代码在chiled中应该是不会再执行!

12、进程上下文和中断上下文详解

用户空间的应用程序,通过系统调用,进入内核空间。这个时候用户空间的进程要传递 很多变量、参数的值给内核,内核态运行的时候也要保存用户进程的一些寄存 器值、变量等。所谓的“进程上下文”,可以看作是用户进程传递给内核的这些参数以及内核要保存的那一整套的变量和寄存器值和当时的环境等

硬件通过触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的 一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。所谓的“ 中断上下文”,其实也可以看作就是硬件传递过来的这些参数和内核需要保存的一些其他环境(主要是当前被打断执行的进程环境)

[简单理解:设备运行过程中,有两部分软件将可能被运行,即用户程序和系统内核,某个应用程序在执行时,可能通过ioctl等函数访问内核,内核收到此访问后,cpu将运行内核对应函数代码段,这时要保存当前环境信息,以保证内核代码执行后回到对应的应用程序代码段,这就是进程上下文;对于中断上下文仅内核存在中断处理,与单片机中断性质一样]

LINUX完全注释中的一段话:

当一个进程在执行时,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容被称 为该进程的上下文。当内核需要切换到另一个进程时,它需要保存当前进程的 所有状态,即保存当前进程的上下文,以便在再次执行该进程时,能够必得到切换时的状态执行下去。在LINUX中,当前进程上下文均保存在进程的任务数据结 构中。在发生中断时,内核就在被中断进程的上下文中,在内核态下执行中断服务例程。但同时会保留所有需要用到的资源,以便中继服务结束时能恢复被中断进程 的执行。

进程上下文是一种内核所处的操作模式,此时内核代表进程执行--例如执行系统调用或运行内核线程。
上下文context: 上下文简单说来就是一个环境,相对于进程而言,就是进程执行时的环境。具体来说就是各个变量和数据,包括所有的寄存器变量、进程打开的文件、内存信息等。
    一个进程的上下文可以分为三个部分:用户级上下文、寄存器上下文以及系统级上下文。
    用户级上下文: 正文、数据、用户堆栈以及共享存储区;
    寄存器上下文: 通用寄存器、程序寄存器(IP)、处理器状态寄存器(EFLAGS)、栈指针(ESP);
    系统级上下文: 进程控制块task_struct、内存管理信息(mm_struct、vm_area_struct、pgd、pte)、内核栈。

    当发生进程调度时,进行进程切换就是上下文切换(context switch).操作系统必须对上面提到的全部信息进行切换,新调度的进程才能运行。而系统调用进行的模式切换(mode switch)。模式切换与进程切换比较起来,容易很多,而且节省时间,因为模式切换最主要的任务只是切换进程寄存器上下文的切换。 

13、进程终止方式

在Linux中进程退出分为了正常退出和异常退出两种。

1>正常退出

a. 在main()函数中执行return 。

b.调用exit()函数

c.调用_exit()函数

2>异常退出

a.调用abort函数

b.进程收到某个信号,而该信号使程序终止。

不管 是那种退出方式,系统最终都会执行内核中的同一代码。这段代码用来关闭进程所用已打开的文件描述符,释放它所占用的内存和其他资源。

3>_exit()和 exit()区别:

a._exit()执行后立即返回给内核,而exit()要先执行一些清除操作,然后将控制权交给内核。

b. exit() 和 _exit()区别之一: 前者支持调用用户自定义的清除程序(atexit函数注册)

c. 调用_exit函数时,其会关闭进程所有的文件描述符,清理内存以及其他一些内核清理函数,但不会刷

新流(stdin, stdout, stderr  ...).   exit函数是在_exit函数之上的一个封装,其会调用_exit,并在

调用之前先刷新流。

14、copy-on-write技术

fork会将调用进程的所有内容原封不动的拷贝到新产生的子进程中去,这些拷贝的动作很消耗时间,而如果fork完之后我们马上就调用exec,这些辛辛苦苦拷贝来的东西又会被立刻抹掉,这看起来非常不划算,于是人们设计了一种"写时拷贝(copy-on-write)"技术,使得fork结束后并不立刻复制父进程的内容,而是到了真正使用的时候才复制,这样如果下一条语句是exec,它就不会白白作无用功了,也就提高了效率。

15、后台程序运行需注意几点:

在后台运行作业时要当心:需要用户交互的命令不要放在后台执行,因为这样你的机器就会在那里傻等。不过,作业在后台运行一样会将结果输出到屏幕上,干扰你的工作。如果放在后台运行的作业会产生大量的输出,最好使用下面的方法把它的输出重定向到某个文件中:
command >out.file 2>&1 &

16、fflush函数

标准C的fflush()支持刷新输出缓冲区,对于输入缓冲区无定义

免责声明:文章转载自《[LINUX-04]linux进程、调度、线程、进程上下文等几点理解》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇js中动态载入css js样式C#调用Axis2发布的带SoapHeader用户验证的WebService下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

kubernetes配置(kubeconfig)对多集群的访问

配置对多集群的访问 本文展示如何使用配置文件来配置对多个集群的访问。 在将集群、用户和上下文定义在一个或多个配置文件中之后,用户可以使用kubectl config use-context命令快速地在集群之间进行切换。 注意:用于配置集群访问的文件有时被称为kubeconfig 文件。 这是一种引用配置文件的通用方式,并不意味着存在一个名为kubecon...

QEMU1.3.0的源码分析三:user model之linux

从源码目录来看,user model有两块内容bsd-user和linux-user。我主要研究了下linux-user这种情况。首先要提一下通常容易关注的焦点,linux-user下的函数入口点:/源码目录/linux-user/main.c中的Line:3388    int main(int argc, char **argv, char **env...

在ThreadPool.QueueUserWorkIte 的回调函数中发生未处理异常导致了应用程序重启

用户登陆Session丢失,可能是因为应用程序发生错误而导致重启。这次遇到这情况是由于使用了ThreadPool.QueueUserWorkItem, 其中回调函数执行时发生未处理的异常,导致了ASP.NET 应用程序意外退出。参考:在 .NET Framework 2.0 中未处理的异常导致基于 ASP.NET 的应用程序意外退出(http://sup...

函数式编程-compose与pipe

函数式编程中有一种模式是通过组合多个函数的功能来实现一个组合函数。一般支持函数式编程的工具库都实现了这种模式,这种模式一般被称作compose与pipe。以函数式著称的Ramda工具库为例。 const R = require('ramda'); function inc (num) { return ++num; } const fun1 = R.c...

iOS- CoreData 数据库管理利器!

1.前文                              上次用SQLite3实现了数据管理,这次准备用CoreData来实现。 Core Data 是iOS SDK 里的一个很强大的框架,允许程序员以面向对象的方式储存和管理数据。使用Core Data框架,程序员可以很轻松有效地通过面向对象的接口管理数据 相比SQLite3来说,用CoreDa...

VC++或QT下 高精度 多媒体定时器

在VC编程中,用SetTimer可以定义一个定时器,到时间了,就响应OnTimer消息,但这种定时器精度太低了。如果需要精度更高一些的定时器(精 确到1ms),可以使用下面的高精度多媒体定时器进行代码优化,可以达到毫秒级的精度,而且使用方便。先要包含头文件"mmsystem.h"和库文 件"winmm.lib"。  虽然Win95下可视化开发工具如VC、D...