Linux 内核、进程调度、进程通信、多线程、协程

Linux内核

操作系统是什么

内核是什么

从功能层面上来说,内核就是一个中间层,软件和硬件之间交互的中间层,链接层

从其他方面理解内核 系统调用,开放了很多接口;资源管理

内核实现的策略

宏内核

微内核

内核包含哪些核心的模块

进程的调度与切换

内存管理

虚拟内存机制

和网络交互的地方

设备驱动程序

进程通信机制&锁

其他模块


Linux进程调度

进程分类

实时进程   用户交互的进程,需要及时响应

普通进程   如压缩文件,视频的编码解码

上下文切换

上下文切换指的是内核CPU上对进程或者线程进行切换。上下文切换过程中的信息被保存在进程控制块(PCB-Process Control Block)中。PCB又被称作切换帧(SwitchFrame)。上下文切换的信息会一直被保存在CPU的内存中,直到被再次使用。

执行环境的变化

调度算法

FCFS  先来先服务调度算法

SJF   短作业(进程)优先调度算法

SRTF  最短剩余时间优先算法

HRRF  响应比高者优先算法

PS   优先级调度算法

RR   时间片轮转法

MLFQ  多级反馈队列调度算法

进程队列

全局队列

局部队列

进程优先级

查看进程优先级的命令 ps -l

nice值

nice值越高,优先级越低

用户可以设置的值,这个值是来影响优先级

Linux进程优先级和nice值 - leno米雷 - 博客园 (cnblogs.com)

优先级和nice的范围

nice  -20~19

进程优先级0~139

实时进程的优先级是0~100

普通进程的优先级是100~139

静态优先级

nice值来决定的优先级,权利在用户,用户在一开始就设定优先级,同时可以更改

动态优先级

内核来决定的,内核自动修改优先级

Linux调度器

O(n)调度器     cpu进程队列

O(1)调度器    优先级映射成了一个bitmap

CFS调度器

【原创】(一)Linux进程调度器-基础 - LoyenWang - 博客园 (cnblogs.com)

linux调度器源码分析 - 概述(一) - tolimit - 博客园 (cnblogs.com)


进程通信

  • 管道    分为无名管道pipe和 命名管道named pipe
  • 消息队列 message
  • 信号 signal
  • 共享内存  shared memory
  • 信号量 semaphore
  • 套接字 socket    可用于不同系统之间,管道和消息队列只能在同一系统

进程间通讯的7种方式_zhaohong_bo的专栏-CSDN博客_进程间通信


信号

软中断信号(signal,又简称为信号)用来通知进程发生了事件。

注意,信号只是用来通知某进程发生了什么事件,无法给进程传递任何数据,进程对信号的处理方法有三种:

1)第一种方法是,忽略某个信号,对该信号不做任何处理,就象未发生过一样。

2)第二种是设置中断的处理函数,收到信号后,由该函数来处理。

3)第三种方法是,对该信号的处理采用系统的默认操作,大部分的信号的默认操作是终止进程。

signal库函数 

signal库函数可以设置程序对信号的处理方式。

函数声明:

sighandler_t signal(int signum, sighandler_t handler);

参数signum表示信号的编号。

参数handler表示信号的处理方式,有三种情况:

1)SIG_IGN:忽略参数signum所指的信号。

2)一个自定义的处理信号的函数,信号的编号为这个自定义函数的参数。

3)SIG_DFL:恢复参数signum所指信号的处理方法为默认值。 

程序员不关心signal的返回值。

发送信号

Linux操作系统提供了kill命令向程序发送信号,C语言也提供了kill库函数,用于在程序中向其它进程或者线程发送信号。

函数声明

int kill(pid_t pid, int sig);

kill函数将参数sig指定的信号给参数pid 指定的进程。

参数pid 有几种情况:

1)pid>0 将信号传给进程号为pid 的进程。

2)pid=0 将信号传给和目前进程相同进程组的所有进程,常用于父进程给子进程发送信号,注意,发送信号者进程也会收到自己发出的信号。

3)pid=-1 将信号广播传送给系统内所有的进程,例如系统关机时,会向所有的登录窗口广播关机信息。

sig:准备发送的信号代码,假如其值为零则没有任何信号送出,但是系统会执行错误检查,通常会利用sig值为零来检验某个进程是否仍在运行。

返回值说明: 成功执行时,返回0;失败返回-1,errno被设为以下的某个值。

EINVAL:指定的信号码无效(参数 sig 不合法)。

EPERM:权限不够无法传送信号给指定进程。

ESRCH:参数 pid 所指定的进程或进程组不存在。


共享内存

共享内存(Shared Memory)就是允许多个进程访问同一个内存空间,是在多个进程之间共享和传递数据最高效的方式。

共享内存并未提供锁机制,也就是说,在某一个进程对共享内存的进行读写的时候,不会阻止其它的进程对它的读写。如果要对共享内存的读/写加锁,可以使用信号灯。

shmget函数

shmget函数用来获取或创建共享内存,它的声明为:

int shmget(key_t key, size_t size, int shmflg);

参数key是共享内存的键值,是一个整数,typedef unsigned int key_t,是共享内存在系统中的编号,不同共享内存的编号不能相同,这一点由程序员保证。key用十六进制表示比较好。

参数size是待创建的共享内存的大小,以字节为单位。

参数shmflg是共享内存的访问权限,与文件的权限一样,0666|IPC_CREAT表示全部用户对它可读写,如果共享内存不存在,就创建一个共享内存。

shmat函数

把共享内存连接到当前进程的地址空间。它的声明如下:

void *shmat(int shm_id, const void *shm_addr, int shmflg);

参数shm_id是由shmget函数返回的共享内存标识。

参数shm_addr指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。

参数shm_flg是一组标志位,通常为0。

调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败返回-1.

shmdt函数

该函数用于将共享内存从当前进程中分离,相当于shmat函数的反操作。它的声明如下:

int shmdt(const void *shmaddr);

参数shmaddr是shmat函数返回的地址。

调用成功时返回0,失败时返回-1.

shmctl函数

删除共享内存,它的声明如下:

int shmctl(int shm_id, int command, struct shmid_ds *buf);

参数shm_id是shmget函数返回的共享内存标识符。

参数command填IPC_RMID。

参数buf填0。

解释一下,shmctl是控制共享内存的函数,其功能不只是删除共享内容,但其它的功能没什么用,所以不介绍了。

注意,用root创建的共享内存,不管创建的权限是什么,普通用户无法删除。

ipcs -m可以查看系统的共享内存,内容有键值(key),共享内存编号(shmid),创建者(owner),权限(perms),大小(bytes)。

ipcrm -m 共享内存编号,可以手工删除共享内存


信号量

信号量(信号灯)本质上是一个计数器,用于协调多个进程(包括但不限于父子进程)对共享数据对象的读/写。它不以传送数据为目的,主要是用来保护共享资源(共享内存、消息队列、socket连接池、数据库连接池等),保证共享资源在一个时刻只有一个进程独享。

semget函数

semget函数用来获取或创建信号量,它的原型如下:

int semget(key_t key, int nsems, int semflg);

semctl函数

该函数用来控制信号量(常用于设置信号量的初始值和销毁信号量),它的原型如下:

int semctl(int semid, int sem_num, int command, ...);

semop函数

该函数有两个功能:1)等待信号量的值变为1,如果等待成功,立即把信号量的值置为0,这个过程也称之为等待锁;2)把信号量的值置为1,这个过程也称之为释放锁。

int semop(int semid, struct sembuf *sops, unsigned nsops);

多线程

和多进程相比,多线程是一种比较节省资源的多任务操作方式。

启动一个新的进程必须分配给它独立的地址空间,每个进程都有自己的堆栈段和数据段,系统开销比较高,进行数据的传递只能通过进行间通信的方式进行。

在同一个进程中,可以运行多个线程,运行于同一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享全局变量和对象,启动一个线程所消耗的资源比启动一个进程所消耗的资源要少。

创建线程

在Linux下,采用pthread_create函数来创建一个新的线程,函数声明:

函数声明:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

参数thread为为指向线程标识符的地址。

参数attr用于设置线程属性,一般为空,表示使用默认属性。

参数start_routine是线程运行函数的地址,填函数名就可以了。

参数arg是线程运行函数的参数。新创建的线程从start_routine函数的地址开始运行,该函数只有一个无类型指针参数arg。若要想向start_routine传递多个参数,可以将多个参数放在一个结构体中,然后把结构体的地址作为arg参数传入,但是要非常慎重,程序员一般不会这么做。

在编译时注意加上-lpthread参数,以调用静态链接库。因为pthread并非Linux系统的默认库。

线程的终止

 如果进程中的任一线程调用了exit,则整个进程会终止,所以,在线程的start_routine函数中,不能采用exit。

线程的终止有三种方式

1)线程的start_routine函数代码结束,自然消亡。

2)线程的start_routine函数调用pthread_exit结束。

3)被主进程或其它线程中止。

pthread_exit函数的声明如下:

void pthread_exit(void *retval);

参数retval填空,即0。


线程同步

对多线程来说,资源是共享的,基本上不存在不允许访问的情况,但是,共享的资源在某一时间点只能有一个线程占用,所以需要给资源加锁。

线程的锁的种类有互斥锁、读写锁、条件变量、自旋锁、信号灯。

互斥锁

互斥锁机制是同一时刻只允许一个线程占有共享的资源

初始化锁

int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr);

阻塞加锁

int pthread_mutex_lock(pthread_mutex *mutex);

非阻塞加锁

int pthread_mutex_trylock( pthread_mutex_t *mutex);

解锁

int pthread_mutex_unlock(pthread_mutex *mutex);

销毁锁(此时锁必需unlock状态,否则返回EBUSY)

int pthread_mutex_destroy(pthread_mutex *mutex);

协程

协程,又称微线程,纤程。英文名Coroutine。

C/C++ 语言本身是不能天然支持协程的。

现有的 C++ 协程库均基于两种方案:利用汇编代码控制协程上下文的切换,以及利用操作系统提供的 API 来实现协程上下文切换

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值