欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

面试笔试中的操作系统问题

程序员文章站 2024-03-17 12:59:34
...

关于操作系统的问题吧

1:线程和进程

https://blog.csdn.net/limingandritchie/article/details/61195918 靠背的概念

2:进程中通信的方式

https://www.cnblogs.com/LUO77/p/5816326.html
先贴一个吧具体的等看完apue再来写总结吧

3 计算机的启动过程蛮有意思的,可以看一看,了解就好

https://www.cnblogs.com/mq0036/p/7125810.html

4 请分别简单说一说进程和线程以及它们的区别

进程是具有一定功能的关于某个数据合集的一次运行活动,是资源调度和分配的一个基本单位
关于进程的信息储存在PCB中,主要有程序计数器,堆栈,全局变量,内存地址阿,文件信息,进程号,等等,寄存器等等
线程是CPU调度和分配的基本单位,线程一般共享进程的信息,但是也有自己的信息,比如程序计数器,堆栈
寄存器,状态等等
多进程的资源是不共享的,因此独立性更强,内存空间是互相独立的,安全性较强,但是开销较多速度较慢
多线程共享资源,比较时和多处理器系统,线程的创建销毁,调度更加快速,因此多线程速度更快,但是
稳定性较差

5 进程通信的方式有哪些

https://www.cnblogs.com/LUO77/p/5816326.html
1 管道,是一种半双工通信方式,只允许数据单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
2 命名管道,是一种半双工,但是取消了只能在父子进程之间传递的限制
3 流管道,全双工
4 消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
5 共享内存:是映射一段能被进程共享的内存端,以达到通信的方法,是最快的IPC方式
6 信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
7 套接字Socket:套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
8 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生

线程可以再分为两类:

一类是用户级线程(user level thread)。对于这类线程,有关线程管理的所有工作都由应用程序完成,内核意识不到线程的存在。在应用程序启动后,操作系统分配给该程序一个进程号,以及其对应的内存空间等资源。应用程序通常先在一个线程中运行,该线程被成为主线“程。在其运行的某个时刻,可以通过调用线程库中的函数创建一个在相同进程中运行的新线程。 用户级线程的好处是非常高效,不需要进入内核空间,但并发效率不高。

另一类是内核级线程(kernel level thread)。对于这类线程,有关线程管理的所有工作由内核完成,应用程序没有进行线程管理的代码,只能调用内核线程的接口。内核维护进程及其内部的每个线程,调度也由内核基于线程架构完成。内核级线程的好处是,内核可以将不同线程更好地分配到不同的CPU,以实现真正的并行计算。

事实上,在现代操作系统中,往往使用组合方式实现多线程,即线程创建完全在用户空间中完成,并且一个应用程序中的多个用户级线程被映射到一些内核级线程上,相当于是一种折中方案。

线程同步:

1 互斥量:表示对共享资源一次只能有一个线程访问,而其他想要访问共享资源的线程必须等待拥有共享资源的放弃
2 信号量:它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。
3 事件:用事件通知的方式控制线程同步,可以用于实现多线程优先级的比较操作
4 读写锁: 有三种状态,不加锁,加读锁,加写锁,当处于写锁状态时,不允许任何的加锁操作,本质上时互斥锁
当处于读锁状态时,允许加读锁,适用于大量读操作的数据结构
5 自旋锁:与互斥锁类似,但是不是通过休眠进程使进程阻塞,而是获取锁之前一直处于忙等状态,适用于
持有锁的时间较少,而且线程并不希望在重新调度上花太多的成本

什么是缓冲区溢出?有什么危害?其原因是什么?

缓冲区为暂时置放输出或输入资料的内存。

缓冲区溢出是指当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法数据上。

缓冲区溢出是一种非常普遍、非常危险的漏洞,在很多软件与操作系统都存在这种问题。
计算机中,缓冲区溢出会造成的危害主要有以下两点:

程序崩溃,导致拒绝服务
跳转并且执行一段恶意代码
造成缓冲区溢出的主要原因是程序中没有仔细检查用户输入是否合理。

死锁

主要是指在两个或多个并发的进程中,进程持有某些资源,而又等待其他进程所拥有的资源,从而造成了一种
互相等待的状态,如果没有外力的干预就会一直保持这种状态

主要有四种条件:
1 互斥,某些资源同一时间只能被一个进程所拥有
2 占用并等待,一个进程因请求资源而阻塞时,对已获得资源保持不放
3 不抢占,即要等待进程主动释放资源,不能抢占
4 循环等待条件:即资源请求图有环

有三种方法解决死锁问题:
1 死锁防止,主要用限定进程申请资源的方式以保证不会进入死锁状态,例如规定进程申请资源时,不能占用其他资源,一次性申请所有资源,在没有资源时才能申请资源,要求每个资源按照递增的顺序申请资源。。
但是这种方法资源利用率比较地
2 死锁避免,是指动态的检测每一次申请是否会导致死锁,不会则允许申请,否则不允许,
从而产生出,如何判定安全性算法,资源请求算法,其中银行家算法是代表
3 假设永远不会产生死锁,这种方法需要判定是否有死锁状态,以及如果出现死锁状态怎么处理了,是一次性释放所有死锁的进程,还是一个一个释放知道没有为止,还是抢占处于死锁状态的进程

银行家算法:

进程有哪几种状态

就绪,运行,等待
就绪->运行
运行->等待
等待->就绪
运行->就绪

中断与系统调用

中断

所谓中断是指cpu在执行某一个任务的时候,收到中断后,停止执行当前的任务,转而去处理这个中断
等待中断处理完后,再回去执行这个程序
中断一般分为三种:
1 因为计算机硬件异常或故障所发出的异常,称为内部异常
2 执行了某些特殊指令所引发的中断成为软中断
3 外部设备所发出的中断,成为外部中断

与中断有关的当然是中断处理程序拉,用来专门处理中断的的程序,成为中断处理程序,
寻找中断程序在哪的成为中断向量

另外一个是有关中断的优先级
机器中断 > 时钟中断 > 磁盘 > 网络设备 > 终端 > 软件中断

系统调用

首先我们知道人物再操作系统上的执行分为用户态和内核态
当应用程序一般再用户态执行,但当应用程序需要操作系统的某些服务时,就需要进入到内核态
向操作系统发出调用服务的请求
当系统发出系统调用时,程序就会从用户态转为内核态,知道调用完成,返回结果给应用程序,
回到用户态

户态和核心态之间的区别

用户态能使用自己的内存地址和指令,内核态可以使用某些特殊的指令,
这些特殊的指令用户态不能调用

IO多路复用

IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合:

当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。
当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。
如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。
如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。
如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。
与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。

常见的IO复用实现
select(Linux/Windows/BSD Unix), epoll(Linux),kqueue(BSD/Mac OS X)

IPC实例:

1 管道:半双工通信,用于父子进程间
linux中的示例:

#include<unistd.h>
#include<stdio.h>
#include<string.h>
int main()
{
	int pipefd[2];
	pipe(pipefd);
	pid_t pid;
	char buf[10];
	if((pid=fork())<0){
		printf("fork error\n");
	}
	else if(pid>0){
		sleep(2);
		close(pipefd[1]);
		printf("fsfsf");
		memset(buf,0,sizeof(buf));
		read(pipefd[0],buf,5);
	//	buf[5] = 0;
		//printf("%d\n",strlen(buf));
		printf("%s\n",buf);
		write(1,buf,5);
	}
	else{
		close(pipefd[0]);
		write(pipefd[1],"hello",5);
	}
	return 0;
}

2 popen pclose

popen函数
FILE *popen(const char *cmdstring,char *type)
是指先创建一个管道,fork一个子进程,关闭未使用的管道端,然后exec执行cmdstring,然后返回一个文件指针,模式w绑定cmdstring的标准输入,r绑定cmdstring的标准输出

3 协同进程

协同进程是指某个进程产生另一个进程的输入,而又读入其输出则成为协同进程

一般用两个管道完成

协程版A+B

#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
void sig_nal(int sig)
{
	printf("SIGPIPE CAUGHT\n");
	exit(1);
}
int main()
{
	int fd1[2];
	int fd2[2];
	int n;
	pid_t pid;
	char line[1024];
	pipe(fd1);
	pipe(fd2);
	signal(SIGPIPE,sig_nal);
	if((pid=fork())<0)
	{
		printf("fork error");
	}
	else if(pid>0)
	{
		close(fd1[0]);
		close(fd2[1]);
		while(fgets(line,1023,stdin)!=NULL)
		{
			n = strlen(line);
			write(fd1[1],line,n);
			n = read(fd2[0],line,1023);
			line[n] = 0;
			fputs(line,stdout);
		}
	}
	else{
		close(fd1[1]);
		close(fd2[0]);
		dup2(fd1[0],STDIN_FILENO);
		dup2(fd2[1],STDOUT_FILENO);
		close(fd1[0]);
		close(fd2[1]);
		execl("./coprocess","coprocess",(char *)0);
	}
}
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
int main()
{
	int n,a,b;
	char line[1024];
	while((n = read(STDIN_FILENO,line,1023))>0)
	{
		line[n]  = 0;
		if(sscanf(line,"%d%d",&a,&b)==2)
		{
			sprintf(line,"%d",a+b);
			n = strlen(line);
			if(write(STDOUT_FILENO,line,n)!=n)
			{
			//	err_sys("write error");
			}
		}
		else{
			write(STDOUT_FILENO,"invalid args\n",13);
			//	err_sys("write error");
		}
	}
}

命名管道

半双工通信模式,取消了只能在相关进程中通信的限制

消息队列

存放在内核中的消息的链接表,由消息队列标识符标识,
在linux中每个队列有一个msqid_ds结构与其对应
用msgget(key,flag) 获得key对应的队列标识符
msgctl(msqid,cmd,msqid_ds *) 控制队列
msgsnd(msqid,const void *ptr, nbytes,flag)
ptr 指向mymesg{ mytype,char} 发送一条消息
msgrcv(msqid,ptr,nbytes,type,flag)
接受一条消息 更新msqid_ds
消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点

信号量

本质上是一个计数器,用于为多个进程提供共享数据的访问

先说一下PV操作:

P操作:
(1) 测试控制该资源的信号量
(2) 若此信号量值为正,则进程使用该资源,然后信号量值减一
(3) 否则,进程进入阻塞队列,如果被唤醒,则返回步骤一
V操作:
(1) 信号值加一,然后唤醒一个阻塞队列的进程

在linux中信号量是一个信号量集
每个信号量集维护一个semid_ds结构
每个信号量是一个无名结构体
semget()函数获得一个信号量ID
semctl() 设置信号量集
semop() 去执行pv操作

共享内存

是映射一段能被进程共享的内存,进程之间能通过内存进行通信,注意同步问题,是最快的IPC方式
shmget() 获得key对应的共享储存id 当key为IPC_PRIVATE时 创建一个新的
shmat() 获得指向shmid的指针
shmctl() 控制
shmdt() 解除联系,引用减少

套接字:

可以用于本机中的进程之间的通信,也可以用于不同主机之间的通信

信号机制

相关标签: 操作系统