|
17 | 17 |
|
18 | 18 | ### <a name="1">1. 进程间的通信方式(IPC)?进程调度方法?</a> |
19 | 19 |
|
20 | | -#### 1.共享内存 |
| 20 | +1.共享内存 <br> |
| 21 | +2.消息队列 <br> |
| 22 | +3.信号 <br> |
| 23 | +4.信号量 <br> |
| 24 | +5.套接字 <br> |
| 25 | +6.普通管道 <br> |
| 26 | +7.有名管道 <br> |
| 27 | + |
| 28 | +- 共享内存 <br> |
21 | 29 |      |
22 | 30 | 可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存 |
23 | 31 | 空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。这种方式 |
24 | 32 | 需要依靠某种同步操作,如互斥锁和信号量等。 |
25 | 33 |
|
26 | | -#### 2.消息队列 |
| 34 | +- 消息队列 <br> |
27 | 35 |      |
28 | 36 | “消息队列”是在消息的传输过程中保存消息的容器。具有写权限得进程可 |
29 | 37 | 以按照一定得规则向消息队列中添加新信息;对消息队列有读权限得进程则可 |
30 | 38 | 以从消息队列中读取信息。 |
31 | | -#### 3.信号 |
| 39 | +- 信号 <br> |
32 | 40 |      |
33 | 41 | 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。 |
34 | | -#### 4.信号量 |
| 42 | +- 信号量 <br> |
35 | 43 |      |
36 | 44 | 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作 |
37 | 45 | 为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因 |
38 | 46 | 此,主要作为进程间以及同一进程内不同线程之间的同步手段。 |
39 | | -#### 5. 套接字 |
| 47 | +- 套接字 <br> |
40 | 48 |      |
41 | 49 | 这是一种更为一般得进程间通信机制,它可用于网络中不同机器之间的进程 |
42 | 50 | 间通信,应用非常广泛。 |
43 | | -#### 6.普通管道 |
| 51 | +- 普通管道 <br> |
44 | 52 |      |
45 | 53 | 普通管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有 |
46 | 54 | 父子关系的进程间使用。 |
47 | | -#### 7.有名管道 |
| 55 | +- 有名管道 <br> |
48 | 56 |      |
49 | 57 | 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 |
50 | 58 |
|
51 | 59 | ### <a name="2">2. 线程间通信的方式?</a> |
52 | | - 锁机制:包括互斥锁、条件变量、读写锁 |
53 | | -* 互斥锁提供了以排他方式防止数据结构被并发修改的方法。 |
54 | | -* 读写锁允许多个线程同时读共享数据,而对写操作是互斥的。 |
55 | | -* 条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条 |
| 60 | +- 锁机制:包括互斥锁、读写锁、条件变量 |
| 61 | + * 互斥锁提供了以排他方式防止数据结构被并发修改的方法。 |
| 62 | + * 读写锁允许多个线程同时读共享数据,而对写操作是互斥的。 |
| 63 | + * 条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条 |
56 | 64 | 件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。 |
57 | 65 |
|
58 | | -信号量机制(Semaphore):包括无名线程信号量和命名线程信号量。 |
| 66 | +- 信号量机制(Semaphore):包括无名线程信号量和命名线程信号量。 |
59 | 67 |
|
60 | | -信号机制(Signal):类似进程间的信号处理。 |
| 68 | +- 信号机制(Signal):类似进程间的信号处理。 |
61 | 69 |
|
62 | 70 |      |
63 | 71 | 线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用 |
64 | 72 | 于数据交换的通信机制。 |
65 | 73 |
|
66 | 74 | ### <a name="3">3. 线程同步的机制。</a> |
| 75 | +Java中与线程同步有关的关键字/类包括: <br> |
| 76 | +volatile、synchronized、Lock、AtomicInteger等concurrent包下的原子类。。。等 |
67 | 77 |
|
68 | 78 | ### <a name="4">4. 操作系统由哪些部分组成?</a> |
69 | 79 |      |
|
80 | 90 |
|
81 | 91 | ### <a name="6">6. 选择一个你熟悉的磁盘臂调度算法进行简单描述。</a> |
82 | 92 |
|
83 | | -1.先来先服务 <br> |
84 | | -2.最短寻道时间优先 <br> |
85 | | -3.SCAN 算法 <br> |
86 | | -4.CSCAN 算法 <br> |
| 93 | +1.FCFS:先来先服务算法 <br> |
| 94 | +2.SSTF:最短寻道时间算法 <br> |
| 95 | +3.SCAN:扫描算法(也叫电梯调度算法)<br> |
| 96 | +4.CSCAN:循环扫描算法 <br> |
| 97 | + |
| 98 | +- FCFS:算法思想非常简单,就是不论初始磁头在什么位置,都是按照服务队列的先 |
| 99 | +后顺序依次处理进程,可以类比队列的先进先出。优点是进程处理起来非常简单,但缺点显而易见,就是平均寻道长度会很长。 |
| 100 | + |
| 101 | + - Java实现: |
| 102 | + |
| 103 | + public class fcfs { |
| 104 | + Scanner x=new Scanner(System.in); |
| 105 | + public int[] position; |
| 106 | + public int num; |
| 107 | + public fcfs() |
| 108 | + { |
| 109 | + System.out.println("Enter the number of process:"); |
| 110 | + num=x.nextInt(); |
| 111 | + position=new int[num]; |
| 112 | + } |
| 113 | + public void input() |
| 114 | + { |
| 115 | + int i=0; |
| 116 | + for(i=0;i<num;i++) |
| 117 | + position[i]=x.nextInt(); |
| 118 | + } |
| 119 | + public void algo() |
| 120 | + { |
| 121 | + int i=1; |
| 122 | + for(i=1;i<=num;i++) |
| 123 | + System.out.println("Process Accessed "+i+" at "+position[i-1]); |
| 124 | + } |
| 125 | + } |
| 126 | + |
| 127 | +- SSTF:最短寻道时间算法,算法本质是贪心,已知磁头的初始位置,则最先被处理就是距离 |
| 128 | +磁头位置最近的进程,处理完成后再处理距离当前磁道最近的进程,直到所有的进程被处理。该 |
| 129 | +算法的优点是平均寻道长度会大大减少,缺点是距离初始磁头较远的服务长期得不到处理,产生 |
| 130 | +“饥饿”现象。具体的思路是:通过循环寻找与初始磁头最近的进程,将进程处理,然后将该进程 |
| 131 | +标记为-1,将初始磁头移动到该进程所在的磁道。然后依次类推,标记为-1的进程不再参与,知 |
| 132 | +道所有的进程都被标记为-1,磁盘调度完成。 |
| 133 | + |
| 134 | + - Java实现 |
| 135 | + |
| 136 | + public class sstfAlg{ |
| 137 | + int num; |
| 138 | + int[][] position; |
| 139 | + int size; |
| 140 | + int initPos; |
| 141 | + int[] sequenceOfProcess ;//存储访问序列 |
| 142 | + int[] sequenceOfNumber; |
| 143 | + Scanner sc = new Scanner(System.in); |
| 144 | + public sstfAlg(int a,int b,int c){ |
| 145 | + //a means the amount of process |
| 146 | + //b means the inital of position |
| 147 | + //c means the size of disk |
| 148 | + num = a; |
| 149 | + position = new int[a][2]; |
| 150 | + sequenceOfProcess = new int[a]; |
| 151 | + sequenceOfNumber = new int[a]; |
| 152 | + initPos = b; |
| 153 | + size = c; |
| 154 | + } |
| 155 | + public void input(){ |
| 156 | + System.out.println("input the number of process:"); |
| 157 | + for(int i=0;i<num;i++){ |
| 158 | + position[i][0] = sc.nextInt(); |
| 159 | + position[i][1] = i+1; |
| 160 | + } |
| 161 | + } |
| 162 | + public void myAlg(){ |
| 163 | + int nearest = 10000; |
| 164 | + int index = 0 ; |
| 165 | + int initPos1 = initPos; |
| 166 | + //复制一个数组用来寻找访问序列 |
| 167 | + int[][] position1 = new int[num][2]; |
| 168 | + for(int i=0 ;i<num;i++){ |
| 169 | + position1[i][0] = position[i][0]; |
| 170 | + position1[i][1] = i+1; |
| 171 | + } |
| 172 | + //寻找磁头访问的序列 |
| 173 | + for(int i=0;i<num;i++){ |
| 174 | + for(int j=0;j<num;j++){ |
| 175 | + if(position1[j][0]!=-1){ |
| 176 | + if(Math.abs(initPos1 - nearest)>Math.abs(position1[j][0]-initPos1)){ |
| 177 | + nearest = position1[j][0]; |
| 178 | + index = j; |
| 179 | + } |
| 180 | + } |
| 181 | + } |
| 182 | + sequenceOfProcess[i] = nearest; |
| 183 | + sequenceOfNumber[i] = index+1; |
| 184 | + position1[index][0] = -1;//-1表示此位置的进程已经放在了访问序列,不在进行查询 |
| 185 | + initPos1 = nearest; |
| 186 | + nearest = 10000; |
| 187 | + } |
| 188 | + |
| 189 | + for(int i=0;i<num;i++){ |
| 190 | + System.out.println("进程"+sequenceOfNumber[i]+"在磁道"+sequenceOfProcess[i]+"完成"); |
| 191 | + } |
| 192 | + } |
| 193 | + } |
| 194 | + |
| 195 | +- SCAN:磁头仅沿一个方向进行扫描,在扫描途中完成所有没有完成的请求,直到磁头到达磁盘在这个方向上的最后一个磁道或者这个方向上最后一个请求所在的磁道。利用数组存储进程和磁道编号,依据给定的初始磁头,先找到初始磁头在哪两个进程之间,然后向内扫描。当磁头扫描到磁盘最内层即磁道0且进程还没有全部被处理,磁头开始向外扫描,直到所有的进程都完成。 |
| 196 | + |
| 197 | + - Java实现 |
| 198 | + |
| 199 | + class scanAlgo{ |
| 200 | + Scanner sc = new Scanner(System.in); |
| 201 | + int num; //进程数量 |
| 202 | + int[] position1; |
| 203 | + int initPos; //磁头初始位置 |
| 204 | + public scanAlgo(){ |
| 205 | + System.out.println("input the amount of process:"); |
| 206 | + num = sc.nextInt(); |
| 207 | + position1 = new int[num+1]; |
| 208 | + System.out.println("input the initial position:"); |
| 209 | + initPos = sc.nextInt(); |
| 210 | + |
| 211 | + } |
| 212 | + public void input(){ |
| 213 | + System.out.println("input the number of process:"); |
| 214 | + for(int i=0;i<num;i++){ |
| 215 | + position1[i] = sc.nextInt(); //记录进程所在的磁道号 |
| 216 | + } |
| 217 | + } |
| 218 | + public void adjust(){ |
| 219 | + //按照磁道编号将进程排序,就是一个冒泡排序 |
| 220 | + for(int i=0;i<num;i++){ |
| 221 | + for(int j=1;j<num-i;j++){ |
| 222 | + if(position1[j-1] > position1[j]){ |
| 223 | + int temp = position1[j]; |
| 224 | + position1[j] = position1[j-1]; |
| 225 | + position1[j-1] = temp; |
| 226 | + } |
| 227 | + } |
| 228 | + } |
| 229 | + } |
| 230 | + public void algo(){ |
| 231 | + //寻找磁头初始位置在哪两个进程之间 |
| 232 | + input(); |
| 233 | + adjust(); |
| 234 | + int init; |
| 235 | + for(init=0;init<num-1;init++){ |
| 236 | + if(position1[init] <= initPos && position1[init+1] > initPos) |
| 237 | + break; |
| 238 | + //此时得到的init值就是磁头初始位置 |
| 239 | + } |
| 240 | + int start = init; |
| 241 | + //磁头先向里扫描 |
| 242 | + for(int i=start;i>=0;i--){ |
| 243 | + System.out.println("The First Time Scan:"+"Process"+position[i][1]+"At Position"+position[i][0]+"Completed"); |
| 244 | + } |
| 245 | + } |
| 246 | + //磁头开始从初始位置向外扫描 |
| 247 | + if(position1[init+1]!=0){ |
| 248 | + System.out.println("This Is the Track 0"); |
| 249 | + } |
| 250 | + for(int i=start+1;i<num;i++){ |
| 251 | + System.out.println("The Second Time Scan:"+"Process"+position[i][1]+"At Position"+position[i][0]+"Completed"); |
| 252 | + } |
| 253 | + } |
| 254 | + } |
| 255 | + } |
| 256 | + |
| 257 | +- CSCAN:在磁盘扫描算法的基础上改变磁头的扫描路径:扫描到最内层之后从最外层向内继续扫描,即扫描方向一致。 |
| 258 | +该算法的思路与扫描算法基本一致,也使用二维数组进行进程编号和进程所在磁道号的存储,算法的不同之处在于当磁 |
| 259 | +头扫描到磁盘的最内层时,磁头跳转到磁盘最外层重新向内扫描,这样就可以有效的避免将已经扫描过的磁道重新扫描 |
| 260 | +一次,降低了平均寻到距离。 |
87 | 261 |
|
| 262 | + - Java实现 |
| 263 | + |
| 264 | + class cscanAlg{ |
| 265 | + Scanner sc = new Scanner(System.in); |
| 266 | + int num; |
| 267 | + int[][] position ; |
| 268 | + int initPos; |
| 269 | + int size; |
| 270 | + public cscanAlg (){ |
| 271 | + System.out.println("input the amount of process:"); |
| 272 | + num = sc.nextInt(); |
| 273 | + position = new int[num+1][2]; |
| 274 | + System.out.println("input the initial position :"); |
| 275 | + initPos = sc.nextInt(); |
| 276 | + System.out.println("input the size of Disk:"); |
| 277 | + size = sc.nextInt(); |
| 278 | + } |
| 279 | + public void input(){ |
| 280 | + System.out.println("input the number of process:"); |
| 281 | + for(int i = 0;i<num;i++ ){ |
| 282 | + position[i][0] = sc.nextInt(); |
| 283 | + position[i][1] = i+1; |
| 284 | + } |
| 285 | + } |
| 286 | + public void adjust(){//调整数组中进程的记录顺序 |
| 287 | + for(int i=0;i<num;i++){ |
| 288 | + for(int j=1;j<num-i;j++){ |
| 289 | + if(position[j-1][0]>position[j][0]){ |
| 290 | + int temp1 = position[j][0]; |
| 291 | + int temp2 = position[j][1]; |
| 292 | + |
| 293 | + position[j][0] = position[j-1][0]; |
| 294 | + position[j][1] = position[j-1][1]; |
| 295 | + |
| 296 | + position[j-1][0] = temp1; |
| 297 | + position[j-1][1] = temp2; |
| 298 | + } |
| 299 | + } |
| 300 | + } |
| 301 | + } |
| 302 | + public void algo(){ |
| 303 | + input(); |
| 304 | + adjust(); |
| 305 | + int init; |
| 306 | + |
| 307 | + for(init = 0;init<num-1;init++){ |
| 308 | + if(position[init][0]<initPos && position[init+1][0]>=initPos){ |
| 309 | + break; |
| 310 | + } |
| 311 | + } |
| 312 | + int start = init; |
| 313 | + System.out.println("第一次扫描:"); |
| 314 | + for(int i=start;i>=0;i--){ |
| 315 | + System.out.println("第一次扫描:"+"进程"+position[i][1]+"在磁道"+position[i][0]+"完成"); |
| 316 | + } |
| 317 | + |
| 318 | + if(position[init+1][0]!=0){ |
| 319 | + System.out.println("磁头已经扫描到磁盘最内层:0"); |
| 320 | + } |
| 321 | + if(position[num-1][0]!=size){ |
| 322 | + System.out.println("磁头已经移到磁盘最外层:"+size); |
| 323 | + } |
| 324 | + |
| 325 | + System.out.println("第二次扫描:"); |
| 326 | + for(int i=num-1;i>start;i--){ |
| 327 | + System.out.println("第二次扫描:"+"进程"+position[i][1]+"在磁道"+position[i][0]+"完成"); |
| 328 | + } |
| 329 | + } |
| 330 | + } |
88 | 331 | ### <a name="7">7. 进程和线程的区别?</a> |
89 | 332 |      |
90 | 333 | (1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单 |
|
102 | 345 | 导致系统的开销明显大于创建或撤消线程时的开销。 <br> |
103 | 346 |
|
104 | 347 | ### <a name="8">8. 操作系统的换页方法。</a> |
105 | | -FIFO、LRU、OPT 等。 |
| 348 | +FIFO、LRU、OPT 等。 <br> |
| 349 | + |
| 350 | +这三个置换算法,或者说缓存调度算法,其实来源于操作系统的页置换算法。 <br> |
| 351 | +FIFO:即 First In, First Out 。 <br> |
| 352 | +LRU: Least recently used,最近最少使用算法。即是将最近最少使用的对象踢出内存。 <br> |
| 353 | +OPT: Optimal,最优替换,也就是上帝模式。它是考虑当前内存中的对象,以及将来要放进 |
| 354 | +内存的对象,然后,将在最远的将来才被访问的页面踢出内存。所以,这个算法在转换时,需 |
| 355 | +要把将来即将放进内存的对象考虑进去,才能找到要踢出内存的对象。 <br> |
| 356 | + |
| 357 | +一.FIFO:First In, First Out,先进先出算法 |
| 358 | +1.1 先进先出算法基本思想: <br> |
| 359 | +     |
| 360 | + 淘汰最先进入的页面,选择在内存中驻留最久的页面的予以淘汰。 |
| 361 | +基本思想就是将先进入队列的页面先淘汰掉,如果该页面后期被命中,那也不将它的步数重置, |
| 362 | +而是按照它第一次进入页面开始记步数。 <br> |
| 363 | +1.2具体操作思想 <br> |
| 364 | + <br> |
| 365 | + |
| 366 | +二. LRU: Least recently used,最近最少使用算法。即是将最近最少使用的对象踢出内存。 |
| 367 | +2.1 LRU置换算法基本思想: <br> |
| 368 | +     |
| 369 | + Lru算法和fifo最大相似点就是淘汰前向步数最大的页面,也就是淘汰页面的判断依据是该 |
| 370 | +页面的从前到后的步数统计,越大表明越是长时间为用到,所以予以淘汰替换。 |
| 371 | +单很明显是由明显区别的,那就是lru算法当遇到命中时会将该页面重置步数。 <br> |
| 372 | +2.2具体操作思想 <br> |
| 373 | + <br> |
| 374 | + |
| 375 | +三.Optimal: Optimal,最优替换,也就是上帝模式。它是考虑当前内存中的对象,以及将来要放进 |
| 376 | +内存的对象,然后,将在最远的将来才被访问的页面踢出内存。所以,这个算法在转换时,需 |
| 377 | +要把将来即将放进内存的对象考虑进去,才能找到要踢出内存的对象。 <br> |
| 378 | +3.1 最佳置换算法基本思想: |
| 379 | +     |
| 380 | + 将以后永不使用的淘汰,或者是将在最长(未来)时间内不在访问的页面淘汰。由于不能知道或预测谁是最可能永不使用或者长时间使用的页面,所以不能拿它来作为页面置换实际操作中的算法,但是可以用于评估其他算法。 |
| 381 | +(未被命中的即为“缺页”,缺页率=未命中数/总数,淘汰率=替换数/总数) <br> |
| 382 | +3.2具体操作思想 <br> |
| 383 | +     |
| 384 | + 首先有一个页面访问顺序的数列2,3,1,5,6,7,6,3,7,8,2。内存块有3个物理块。 <br> |
| 385 | + <br> |
| 386 | + |
| 387 | + |
106 | 388 | ### <a name="9">9. 哲学家进餐问题的无死锁算法。</a> |
107 | 389 | A.原理:仅当哲学家的左右两支筷子都可用时,才允许他拿起筷子进餐。 <br> |
108 | 390 |
|
|
0 commit comments