1. 程式人生 > >作業系統——第二章筆記(四)

作業系統——第二章筆記(四)

一.程序通訊
程序通訊是指程序之間的資訊交換。
1.低階通訊——程序之間的互斥和同步
訊號量機制是有效的同步工具,但作為通訊工具缺點如下:
(1)效率低(通訊量少)
(2)通訊對使用者不透明(程式設計師實現,作業系統只提供共享儲存器供程式碼操作)
2.高階程序通訊
使用者直接利用作業系統提供的一組通訊命令,高效地傳送大量資料的通訊方式。
作業系統隱藏了程序通訊的細節,對使用者透明,減少了通訊程式編制上的複雜性。
二.程序通訊的型別
高階通訊機制可歸結為四大類
① 共享儲存器系統(操作儲存區方式)
相互通訊的程序共享某些資料結構或共享儲存區,程序之間能夠通過這些空間進行通訊。
a. 基於共享資料結構的通訊方式(低階)
b. 基於共享儲存區的通訊方式(高階)
例:兩臺主機之間QQ訊息的傳送
在傳送端開闢一個快取區,存放傳送的資料,通過物理媒體的傳遞通過網絡卡到接收端的緩衝區。
問題:為什麼QQ傳送的訊息不會出現在瀏覽器上?
解答:每個應用程式都有自己的埠,通過埠找到再各自電腦上的緩衝區,從中傳送或者獲取資料
1)基於共享資料結構
諸程序公用某些資料結構,藉以實現諸程序間的資訊交換。
如生產消費問題,定義共享的資料結構:n個長度的有界緩衝區。
程式設計師:提供對公用資料結構的設定及對程序間同步的處理。
作業系統:提供共享儲存器。
特點:複雜、低效率,還只適合傳遞相對少量的資料。
2)基於共享儲存區(適用於大量資訊傳遞,底層同步處理由作業系統控制)
 在儲存器中劃出了一塊共享儲存區,諸程序可通過對共享儲存區中資料的讀或寫來實現通訊。
 程序通訊前先向系統申請獲得共享儲存區中的一個分割槽,並指定該分割槽的關鍵字;
 若系統已經分給了其他程序,則將該分割槽的描述符返回給申請者,申請者把獲得的共享儲存分割槽連線到本程序上;此後,便可像讀、寫普通儲存器一樣地讀、寫該公用儲存分割槽。多程序藉助該區通訊。
②訊息傳遞系統(發–收方式)
 最廣泛使用的一種,程序間的資料交換,以格式化的訊息為單位。遮蔽底層複雜操作。
 單機:作業系統底層程式設計中的訊息傳遞系統呼叫;
 計算機網路:訊息稱為報文。程式設計師直接利用系統提供的一組通訊命令(原語)進行通訊。(④客戶機-伺服器系統)
③管道通訊(中間檔案方式)
 所謂“管道”,是指用於連線一讀程序和一寫程序以實現通訊的一個共享檔案,又名pipe檔案。
 向共享檔案輸入的寫程序以字元流形式將大量的資料送入管道;而接收管道輸出的讀程序則從管道中接收(讀)資料。
 首創於UNIX系統。其管道機制需提供三方面的協調能力:互斥、同步、確定對方是否存在。
例子:
對管程進行刪除檔案操作:

#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define FIFO “/tmp/myfifo”
main(int argc,char**argv)
{   char buf_r[100];
    int fd;
    int nread;
  /*建立管程*/
   if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))
  printf(“cannot create fifoserver\n”)
printf(“Preparing for reading bytes…\n”);
memset(buf_r,0,sizeof(buf_r));
/*開啟通道*/
fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);
if(fd==-1)
{   perror(“open”);
    exit(1);
}
while(1)
{   memset(buf_r,0,sizeof(buf_r));
    if((nread=read(fd,buf_r,100))==-1)
    {
      if(errno==EAGAIN)
         printf(“no data yet\n”);
    }else
  printf(“read %s from FIFO\n”,buf_r);
  sleep(1);
}
pause();/*暫停,等待訊號*/
unlink(FIFO);//刪除檔案
}

對管程進行寫入資料操作:

#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define FIFO_SERVER “/tmp/myfifo”
main(int argc,char**argv)
{   int fd;
    char w_buf[100];
    int nwrite;
/*開啟管道*/
fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);
if(argc==1)
{     printf(“Please send something\n”)
      exit(-1);
}
strcpy(w_buf,argv[1]);
/*向管道寫入資料*/
if((nwrite=write(td,w_buf,100))==-1)
{   if(errno==EAGAIN)
      printf(“The FIFO has not been read yet.Please try later\n”);
}
else
       printf(“write %s to the FIFO\n”,w_buf);
}

程式設計操作命名管道的例子:

#include<stdio.h>
 #include<string.h>
 #include<unistd.h>
 #include<sys/types.h>
 #include<errno.h>
 #include<fcntl.h>
//建立管道
 int main(int argc,char *argv[])
{
   //pipefile=”/tmp/mypipefile”
   //使用mkfifo函式建立一個FIFO管道
  if((mkfifo(pipefile,0666))<0){
perror(“failed to mkfifo”);
exit(1);}
 printf(“mkfifo successes.name is %s\n”,pipefile);
 return 0;
}
    //讀管道
 int main(int argc,char *argv[]) {
  if(argc!=2) {
   printf("not enough params,give pipefile name\n");
   exit(1);
  }
  char *pipefile;
  pipefile=argv[1];
  char buf[100];
  int fd,i;
  printf("read open namedpipe!\n");
  fd=open(pipefile,O_RDONLY,0);    //只有當讀和寫的兩個open都是執行的時候才可以繼續執行,否則將等待
  printf("ok! namedpipe opened for read!\n");
  i=read(fd,buf,100);       //當沒有寫操作執行時才可讀,否則等待
  buf[i]=0;
  printf("ok! reaed from namedpipe: %s!\n",buf);  
  return 0;
 }
 //寫管道
 int main(int argc,char *argv[]) {
  if(argc!=2) {
   printf("not enough params,give pipefile name\n");
   exit(1);
  }
  char *pipefile;
  pipefile=argv[1];
  int fd;
  char *test="test strings!";
  printf("open namedpipe --%s for write!\n",pipefile);
  fd=open(pipefile,O_WRONLY,0);        //只有當讀和寫的兩個open都是執行的時候才可以繼續執行,否則將等待
  printf("ok! namedpipe --%s opened for write!\n",pipefile);
  sleep(10);
  printf("write wake up! hahaha!\n");
  write(fd,test,strlen(test));
  printf("OK! namedpipe write successfully!\n");
  exit(0);
 }

④Client-Server system
3.訊息傳遞通訊的實現方法
1)直接通訊方式
2)間接通訊方式
三.訊息傳遞系統的實現
單機和網路環境下的高階程序通訊廣泛採用“訊息傳遞”方式,需要考慮的問題:
① 通訊鏈路的建立
② 訊息格式
③ 同步方式
四.認識執行緒
程序的產生是為了提高效率,程序效率低執行緒效率高。
1.執行緒的引入
多道程式管理:追求效率的目的下實現“併發”
利用程序實現的多道程式系統中
程序是一個可擁有資源的獨立單位;
是一個可獨立排程和分派資源的基本單位
併發程度不是隨意設定的:
 併發程序數量不宜過多,切換頻率不宜過高。
 限制併發程度問題所在:程序實體資訊量大,對程序的管理操作越多,與執行時間的比值就越大,執行效率就低。
2.執行緒的屬性
多執行緒OS中,一個程序包括多個執行緒,每個執行緒都是利用CPU的基本單位。
1)輕型實體:只需一點必不可少的、能保證獨立執行的資源。(TCB)
2)獨立排程和分派的基本單位:排程切換迅速且開銷小。
3)可併發執行。
4)共享程序資源:同進程中的執行緒可共享相同的程序地址空間、已開啟檔案、訊號量機構等。
3.執行緒的資訊
TCB管理什麼資訊?
狀態引數
 識別符號、執行狀態、優先順序、暫存器狀態、堆疊、專有儲存器、訊號遮蔽等。
 執行狀態:執行、就緒、阻塞
4. 執行緒的建立和終止
在多執行緒OS中,應用程式啟動時,通常只有一個執行緒(初始化執行緒)在執行,它根據需要再建立若干執行緒。
5.多執行緒系統中的程序
 程序只是用於分配系統資源
 包括多個執行緒
 不是執行實體,執行緒在程序範圍內作為執行實體。
6.執行緒的管理
 同步和通訊機制
1)互斥鎖
 比較簡單的,控制執行緒互斥訪問資源;
 適用於高頻度使用的關鍵共享資料和程式段;
 unlock和lock兩個鎖操作原語;
2)條件變數
 與互斥鎖一起使用
 鎖保證互斥進入臨界區,但利用條件變數使執行緒阻塞
 注意不滿足條件時,wait條件變數:
○1釋放互斥鎖
○2程序阻塞在條件變數指向佇列中
○3被喚醒後要重新再設互斥鎖
3)訊號量
 私用訊號量(private samephore)
 用於同進程的執行緒間同步,資料結構存放在應用程式的地址空間。屬於特定程序,OS感知不到其存在。
 公用訊號量(public samephore)
 用於不同程序間或不同程序中執行緒的同步,資料結構由OS管理,存放在受保護的系統儲存區。
五.執行緒的實現方式
1.核心執行緒KST(kernel-level thread)
 依賴於核心,利用系統呼叫由OS核心在核心空間完成建立、撤消、切換等執行緒工作。
 時間片分配給執行緒,所以多執行緒的程序獲得更多CPU時間。
2.使用者執行緒ULT(user-level thread)
無須利用系統呼叫,不依賴於OS核心。程序利用執行緒庫函式建立、同步、排程和管理控制使用者執行緒。
 排程由應用軟體內部進行,通常採用非搶先式和更簡單的規則,也無需使用者態/核心態切換,速度比kst快。
3.組合方式
核心支援多KST執行緒的管理,同時也允許使用者應用程式級的執行緒管理。

PS:
1.KST優缺點:
 多處理器系統下可實現多執行緒並行
 一個執行緒發起系統呼叫而阻塞,不會影響其它執行緒的執行
 執行緒切換開銷遠小於程序切換
 核心本身也採用多執行緒技術可提高系統執行速度和效率
BAD:
 使用者態執行執行緒,排程和管理執行緒則是核心態。模式的切換開銷大。
2.ULT優缺點:
 使用者執行緒的維護由應用程序完成;核心不瞭解使用者執行緒的存在;執行緒切換不需要核心特權;
 使用者執行緒排程演算法可針對應用優化;
 多執行緒的實現與平臺無關
 一旦系統呼叫引起程序阻塞,則整個程序的所有執行緒都不能執行
 以程序為單位分配cpu,所有在多處理器系統中沒有優勢