在第五章併發與競態中,介紹了乙個當程序需要的資源被其他程序占用,而不得不等待該資源的情形。這裡,要說的則是即便程序得到資源之後,由於資源本身的一些問題而不能預期的完成功能,必須休眠一段時間,直到它的要求得到滿足。兩種情形的區別是顯而易見的,不過在使用上,實在是有點相似。其實最近學的一些東西都是這樣,訊號量,自旋鎖
....
不管他們的內在區別的話,使用時無外乎就是初始化,然後在乙個地方申請,另乙個地方反饋。
先對休眠有乙個基礎的認識先。就是說,程序確實是在執行,需要的東西也有給它了,但是,給它的東西卻不滿足它的要求,於是乎它還是做不了事。怎麼辦呢,就只有讓它等了,當前程序也就休眠了。進入休眠的時候會把它對資源的要求提出來,一旦這個要求得到滿足,休眠的程序就會立刻被喚醒。
然後是關於休眠的兩個需要注意的地方。首先,進入休眠之後,當前程序就算是失去了對作業系統的控制,休眠多久是不確定的,所以肯定不能放在原子上下文。寧外,之前也強調過的,在使用自旋鎖時一定不能休眠,而訊號量方法是允許休眠的。第二個就是在休眠被喚醒時,程式一定要再次檢查要求是否得到滿足,這個一點都不多餘。
作業系統的知識告訴我,以上說的起始就是程序的阻塞了。作業系統會有乙個等待佇列來管理阻塞的程序,要實現休眠的第一步也就是構建乙個等待佇列頭了。如下:
1declare_wait_queue_head(name);
//靜態
2wait_queue_head_t my_queue;
3init_waitqueue_head(
&my_queue);
//動態
下面的方法讓程序進入休眠:
1wait_event(queue, condition)
2wait_event_interruptible(queue, condition)
//可中斷
3wait_event_timeout(queue, condition, timeout)
4wait_event_interruptible_timeout(queue, condition, timeout)
condition
也就是程序提出的要求了,這是乙個布林表示式,當表示式為真時,休眠的程序就會立刻被喚醒。
喚醒用以下函式,這個就沒什麼好講的了
:
1void
wake_up(wait_queue_head_t
*queue);
2void
wake_up_interruptible(wait_queue_head_t
*queue);
之前的scull
專案本身是沒有支援休眠的,但是
scull
原始碼下的
pipe
.c檔案給我們提供了乙個休眠的例項。這是驅動程式跟之前的scull
很是不同,它用到了緩衝區來讀寫資料。這樣才會出現讀寫時阻塞的情況。讀資料時緩衝區為空阻塞,寫資料時緩衝區已滿阻塞。
scullpiep
的裝置結構如下:
1struct
scull_pipe ;
讀取的**如下:
1static
ssize_t scull_p_read (
struct
file
*filp,
char
__user
*buf, size_t count,
2loff_t
*f_pos)320
/*ok, data is there, return something
*/21
if(dev
->
wp >
dev->
rp)22
count
=min(count, (size_t)(dev
->
wp -
dev->
rp));
23else
/**/
24count
=min(count, (size_t)(dev
->
end
-dev
->
rp));
25if
(copy_to_user(buf, dev
->
rp, count))
29dev
->
rp +=
count;
30if
(dev
->
rp ==
dev->
end)
31dev
->
rp =
dev->
buffer;
/**/
32up (
&dev
->
sem);
3334
/*finally, awake any writers and return
*/35
wake_up_interruptible(
&dev
->
outq);
36pdebug(
"\"%s\" did read %li bytes\n
",current
->
comm, (
long
)count);
37return
count;
38}
迴圈的內容。
dev->rp == dev->wp
表示緩衝區為空,這時程序不能順利的讀資料,必須休眠。因為這裡使用了訊號量來管理併發程序,當前程序休眠時必須先釋放訊號量,以便其他程序執行。
wait_event_interruptible(dev->inq, (dev->rp != dev->wp))
就是進入休眠了,被喚醒之後,就接著執行之後的**,第一步也就是重新獲取訊號量了。這裡也並沒有直接退出
while
迴圈,迴圈條件仍需要判斷,之前就說過,這個對要求是否得到滿足的再次判斷是不多餘的。後面的一些讀取操作以前的沒太大區別。
接下來的重點就在於在**喚醒這個休眠中的程序了。其實很簡單,在write
方法完成的時候,執行以下**就行了
:
1*finally
, awake any reader */2
wake_up_interruptible(
&dev
->
inq);
/*blocked in read() and select()
*/
mysql第六章 第六章 mysql日誌
第六章 mysql日誌 一 錯誤日誌 錯誤日誌的預設存放路徑是 mysql 存放資料的地方 hostname.err 1.修改錯誤日誌存放路徑 mysqld log error data mysql mysql.log 2.檢視配置命令 show variables like log error 3...
第六章 指標
1.多位元組資料的位址是在最左邊還是最右邊的位置,不同的機器有不同的規定,這也正是大端和小端的區別,位址也要遵從邊界對齊 2.高階語言的乙個特性就是通過名字而不是位址來訪問記憶體的位置,但是硬體仍然通過位址訪問記憶體位置 3.記憶體中的變數都是義序列的0或1的位,他們可以被解釋為整數或者其他,這取決...
第六章總結
6.1 使用滑鼠 6.1.1 滑鼠時間和滑鼠訊息 根據使用者操作滑鼠時滑鼠的位置,滑鼠訊息分為兩類 客戶區滑鼠訊息和非客戶區滑鼠訊息。1.客戶去滑鼠訊息 2.當滑鼠游標位於視窗的使用者區時,將生成客戶滑鼠訊息。滑鼠訊息和鍵盤訊息有所不同,windows 只將鍵盤有訊息傳送給具有輸入極點的視窗,但滑鼠...