【2016/1】 Unix IPC 信號 共享內存 消息隊列

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/hsgwpj/article/details/50610074

Unix下的IPC

IPC樣例 - github

   kill -l #查看所有信號

kill 不加signum的時候默認發送15號信號

原子操作: 防止被中斷的操作 kill -9 使用的就是這個操作且不可被更改
15號信號是可以被終結的9號信號
除了9與19號信號, 別的信號的操作內容都是可以修改的
ctrl + c : 2號信號 SIGINT
— 用^c關閉不掉的進程就是被1號進程接管了,或者爲了保護它就放在後臺

1.信號

signal()來註冊自己編寫的信號處理(handler)
— 很多信號的默認操作都是退出

信號最終是由內核中轉發送給進程的
— 信號是不可靠的, 是可以被屏蔽的(未決性) 無法保證完全的實時性
— 信號屏蔽時並未消失 只是被延遲了

sigset_t 信號屏蔽字 64位代表64個接受或者不接受的狀態
— 對屏蔽字的操作在signal.h中封裝了
— 製作好屏蔽字後要用sigprocmask來將其適用

調用abort()函數可以給自己發送一個SIGABRT信號
同時這個信號也會被多次free觸發
調用pause()函數進入無限期睡眠, 直到收到一個信號時才被喚醒
調用alarm()函數 在傳入參數的時間到時 發送一個SIGALRM信號

時間編程:
clock_nanosleep()一個高精度的表 如果被打斷 還會記錄剩餘的時間
— 配合sleep() 防止sleep沒有到達預定的掛起時間 還有usleep()
可以用gettimeofday()的毫秒時間作爲隨機數,得到1979到現在秒數
— 更精確的的clock_gettime()
— 系統時間的精度有兩個結構體 timespec 納秒級別 timeval 微秒級別
localtime(從1970到現在的秒數) 格式化輸出年月日時間 輸出tm結構體

系統級別就是/etc/rc.d下的腳本,用init幾就是運行哪個目錄下的服務

** 操作系統啓動過程!
《Unix服務器編程》
《操作系統原理》《現代操作系統》

sigpending() 在屏蔽時間 獲取期間到達的信號(阻塞狀態)
— 獲取信號的同時不用被打斷 而是用自己的方式處理

sigsetjmp() 可以進行goto式的跳躍,但是不建議使用

爲何goto不能在函數間跳轉:
內存空間的衝突,棧內存,代碼段內存等,關鍵字操作在編譯階段,
不能控制指令運行時候的內存分配,只能用系統或者函數調用

SIGCHID 子進程終止時給父進程發的信號
sigsuspend() 臨時替換當前進程的信號屏蔽字 會掛起一直到有信號到達
— 等待的是傳入的屏蔽字中屏蔽的信號以外的信號到達纔會終止
raise(sig) 給自己發一個信號 等同於 kill(getpid(), sig)
sigqueue() 加強版的kill函數 用位操作來製作sigval來傳入參數
sigaction() 註冊信號 同時保存之前的信號操作到一個結構體中
— 結構體中有操作方法的函數指針 同時還存着另一種操作方法
— 另一種操作方法中帶有一個包含很多信息的結構體(siginfo_t)

**tips:
如果用exec之前創建了屏蔽字並且應用了
那麼用exec之後 即使進程空間被替換 進程的控制信息依然保留
所以原來程序對信號的控制依然存在
— 信號管控服務!

進程間通信:
Linux下的IPC ipcs可以查看進程共享的內存段
文件系統 效率較低
信號 用信號傳遞小的信息

2.管道

管道 pipe()-只基於內存 非衍生進程都不能看到
— 管道中的數據是一次性的 傳遞完信息就沒有了
0 號成員來讀 1 號成員來寫
父子進程會複製描述符 但是描述符繼承的是同一條管道
— 描述符指向的空間是共享的
用一條管道傳輸多個進程的內容:
約定內容長度,讓子進程只接受一個長度的內容
管道最大的容量:4096
管道讀完了默認掛起而不是

fd的控制: fcntl()

gbd調試: gdb attach <進程號>
bt: (back trace)查看其中進程的棧針(運行的位置)
detach: 禮貌性的退出
unlimit -c unlimited 解開core dump 的限制
然後把core.文件用gdb閱讀
unlimit -c 0 關閉core file的系統

int mkfifo(const char *pathname, mode_t mode);
製作一個有名管道 使用管道依然要open
但是管道不能長期存儲, 只有在進程運行時可以訪問數據

3.共享內存

每個進程都可以使用的內存, 整個系統範圍有效
內存具有key shmid
key=0 的共享內存表示私有內存 不想被別人使用
但通過shmid既然可以訪問共享內存
共享內存是獨立於進程的,只要不刪除就一直存在
給別的進程對共享內存進行訪問控制的方法

Usage:
shmget() 可以創建或者刷新獲得一塊內存 通過key與大小 返回是一個ID
shmat() 用返回的ID使用一塊內存(映射) *單一進程有效! attach
shmdt() 不再使用內存 don’t attach
shmctl() 對共享內存進行控制信息的更改,獲取或者修改

ipcrm -m shmid 刪除by id
ipcrm -M key 刪除by key
不建議用cmd刪除shm,最好在代碼中shmctl刪除,排除異常情況

tips: 所有有意義的內存都需要初始化, 要麼賦值 要麼memset

製作程序顯示共享內存的值 以16進制按行顯示 第一列是內存地址
strtol() 轉換任意進制

父進程在收到一個信號的時候 bash會給其下所有子進程發送相同的信號

2016-1-17:
cat /proc/sys/kernel/shm* 裏面有有關共享內存的信息

4.消息隊列:

消息只會一條條的收,分條發送和接受

**msgget()** 使用key值來得到消息 返回一個ID值 用來以後收發消息
**msgctl()** 得到控制信息來改變消息隊列的信息(最好在創建消息隊列之前)

— 先獲取msg的控制信息 然後更改之後再存回去 否則可能是垃圾值
msgrcv() / msgsnd() 收發消息 原子操作:不會被另一個進程打斷
— 發送的數據是一個結構體,結構體的首成員必須是一個long的標記值
— 消息的掛起: 發送的時候隊列滿了與接受的時候隊列爲空
— 消息的身份是由type決定的 當recv type爲 0 時直接收隊首的消息
— msgflag爲MSG_EXCEPT 時是除了爲type的第一條消息被收走
— type 爲負值 收絕對值小與等與它的最小值

ls /proc/sys/kernel/msg* 中有msg的宏值與信息

更改內核的一些參數 再/etc/sysctl.conf 中添加參數:
eg: kernel.msgmnb = 2048
(把/proc/sys/中的內容的目錄/改爲點 然後就可以修改了)
sysctl -p 刷新內核參數文件

信號量是一個資源計數器
*互斥鎖:資源計數爲1(有人使用立即臨界,不能被使用)
臨界區 臨界資源-> 某一時刻只能由一個程序接受的資源(鍵盤)
— 同時只能由一個程序來操作臨界區的代碼段的代碼

semget() nsems參數爲信號量級
semctl() 對於信號量進行操作,設定信號量初值等
— 在最開始初始化之後不要隨便更改 否則影響互斥的能力
semop() / semtimedop() 信號操作 pv操作 +-1來加減鎖
***tip: 瞭解一下PV操作
— 系統保護: 如果加鎖的人不在了 系統自動解鎖(UNDO)
— 實現了同步異步

Linux下 C語言基本類型(四字節及以下)的賦值是原子操作

Tips:
夥伴系統原理: 用N個鏈表來管理內存塊 在申請內存時根據內存大小
輪詢合理的內存位置 在把多餘的空間分配到鏈表上
36-> 32 + 32 -> 32 + 4 + 16 + 8 + 4 -> 36 + 16 + 8 + 4
然後把16 8 4 放在限定內存大小爲16 8 4 的內存鏈表上
釋放的時候自動查詢連續的空白內存塊合併 防止內存不連續的問題
十八種內存管理系統技術 MMU

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章