Linux模擬實(shí)現(xiàn)sleep函數(shù)
先來說說工作原理,linux中的sleep函數(shù)能夠讓程序休眠一定的秒數(shù),到時(shí)間后自動(dòng)恢復(fù)運(yùn)行。
實(shí)現(xiàn)思路
設(shè)定睡眠的秒數(shù)
睡眠(掛起)
恢復(fù)運(yùn)行
實(shí)現(xiàn)機(jī)制
設(shè)定睡眠的秒數(shù):采用alarm()函數(shù)設(shè)定需要睡眠的秒數(shù),到時(shí)間后鬧鐘會(huì)發(fā)送SIGALRM信號(hào)給當(dāng)前進(jìn)程。但SIGALRM信號(hào)的默認(rèn)操作是終止進(jìn)程,所以我們需要對(duì)SIGALRM信號(hào)進(jìn)行自定義處理。
睡眠:pause()函數(shù)會(huì)讓當(dāng)前進(jìn)程掛起,直到收到信號(hào)才會(huì)出錯(cuò)返回。
示例程序代碼:模擬實(shí)現(xiàn)sleep使當(dāng)前進(jìn)程每2秒打印”hello yingying\n”
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handler(int signo)//由于程序在睡眠期間什么也不做所以自定義處理函數(shù)不執(zhí)行任何操作
{
}
int mysleep(int time)
{
sigset_t set;
sigemptyset(&set);
struct sigaction act;
struct sigaction oact;
act.sa_handler = handler;//自定義處理函數(shù)
act.sa_mask = set;
act.sa_flags = 0;
sigaction(SIGALRM,&act,&oact);//捕捉鬧鐘信號(hào)自定義處理動(dòng)作
alarm(time);//time秒后給進(jìn)程發(fā)送信號(hào)
pause();//掛起進(jìn)程
int _time = alarm(0);//如果程序被提前喚醒取消鬧鐘
sigaction(SIGALRM,&oact,NULL);//恢復(fù)捕捉信號(hào)的原始狀態(tài)
return _time;
}
int main()
{
while(1)
{
printf("hello yingying\n");
mysleep(2);
}
return 0;
}
問題分析
上述代碼在看似沒有問題可以實(shí)現(xiàn)我們需要的結(jié)果,但是帶 多執(zhí)行流下仍可以正常運(yùn)行嗎?例如在設(shè)定了鬧鐘后當(dāng)前進(jìn)程被切換出去,等再切換回來鬧鐘已經(jīng)響過了,那么當(dāng)前進(jìn)程就會(huì)被永遠(yuǎn)掛起。所以我們需要優(yōu)化上面的程序。
.優(yōu)化方案一:
1.屏蔽SIGALRM信號(hào)
2.alarm(time)
3.解除屏蔽SIGALRM信號(hào)
4.pause()
.優(yōu)化方案二:
1.屏蔽SIGALRM信號(hào)
2.alarm(time)
3.pause()
4.解除屏蔽SIGALRM信號(hào)
這兩種方案大家思考一下可行嗎?應(yīng)該選哪個(gè)呢?
方案選擇
對(duì)于方案一:如果進(jìn)程在解除屏蔽之后,pause()之前的的間隙被切走仍會(huì)造成同樣的問題,進(jìn)程也可能被永遠(yuǎn)掛起。
對(duì)于方案二:程序掛起之后,鬧鐘信號(hào)被屏蔽,一直處于未決狀態(tài),程序無法收到信號(hào),進(jìn)程也就會(huì)被一直掛起。所以方案二是不可以選擇的。
對(duì)于方案一我們可以改進(jìn),使解除阻塞與掛起成為一個(gè)原子操作這樣就可以解決我們的問題了。
解決問題
像方案一這種由時(shí)序問題導(dǎo)致程序出現(xiàn)問題的情況成為競(jìng)態(tài)條件。sigsuspend()函數(shù)可以實(shí)現(xiàn)pause()函數(shù)的掛起功能,同時(shí)也能解決競(jìng)態(tài)條件的問題。sigsuspend()函數(shù)的功能就是-“解除信號(hào)屏蔽”-“掛起進(jìn)程等待信號(hào)”-“執(zhí)行信號(hào)處理函數(shù)”- “出錯(cuò)返回”。所以sigsuspend()函數(shù)函數(shù)同pause()函數(shù)一樣只有出錯(cuò)返回值。在對(duì)程序時(shí)序要求比較嚴(yán)格的程序中一般使用sigsuspend()函數(shù)。
優(yōu)化后的程序代碼
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handler(int signo)
{
}
int mysleep(int time)
{
sigset_t set,oset,susmask;
sigemptyset(&set);
sigaddset(&set,SIGALRM);
sigprocmask(SIG_BLOCK,&set,&oset);
struct sigaction act;
struct sigaction oact;
act.sa_handler = handler;
act.sa_mask = set;
act.sa_flags = 0;
sigaction(SIGALRM,&act,&oact);
alarm(time);
susmask = oset;
sigdelset(&susmask,SIGALRM);
sigsuspend(&susmask);
int _time = alarm(0);
sigaction(SIGALRM,&oact,NULL);
sigprocmask(SIG_BLOCK,&oset,NULL);
return _time;
}
int main()
{
while(1)
{
printf("hello yingying\n");
mysleep(2);
}
return 0;
}這樣我們的sleep函數(shù)的模擬實(shí)現(xiàn)就完成了。
程序結(jié)果

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Centos系統(tǒng)下“無法打開并寫入文件”問題的解決
這篇文章主要給大家介紹了關(guān)于在Centos系統(tǒng)下報(bào):“無法打開并寫入文件”問題的解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12
Linux之路由轉(zhuǎn)發(fā)和SNAT的應(yīng)用方式
這篇文章主要介紹了Linux之路由轉(zhuǎn)發(fā)和SNAT的應(yīng)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
Centos7服務(wù)器下啟動(dòng)jar包項(xiàng)目的最佳方法
這篇文章主要給大家分享介紹了關(guān)于Centos7服務(wù)器下啟動(dòng)jar包項(xiàng)目的最佳方法,文中通過示例代碼以及圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
如何配置apache虛擬主機(jī)的實(shí)例小結(jié)
如果你是第一次配置apache虛擬主機(jī),那么通過閱讀這篇文章你將會(huì)了解到如何實(shí)現(xiàn)apache虛擬主機(jī)配置。其實(shí)要配置好一臺(tái)虛擬主機(jī)沒有想象中那么難2014-01-01
linux系統(tǒng)下如何掛載NTFS移動(dòng)硬盤
用命令行掛載移動(dòng)硬盤是Linux的基本操作之一,雖然目前有些Linux系統(tǒng)能自動(dòng)加載移動(dòng)硬盤,但有些時(shí)候(比如使用Ubuntu Server或其它Linux系統(tǒng)的時(shí)候)仍然需要手動(dòng)操作,下面這篇文章主要介紹了linux系統(tǒng)下如何掛載NTFS移動(dòng)硬盤,需要的朋友可以參考借鑒。2017-01-01
在Debian系的Linux中編譯并安裝ixgbe驅(qū)動(dòng)的教程
這篇文章主要介紹了在Linux中編譯并安裝ixgbe驅(qū)動(dòng)的教程,采用bash shell、適用于Debian、Ubuntu等各種基于Debian的Linux系統(tǒng),需要的朋友可以參考下2015-03-03

