1. 程式人生 > >APUE習題10.5之implementing software timer

APUE習題10.5之implementing software timer

題目:僅使用一個定時器,構造一組函式,使得程序在該單一定時器基礎上可以設定任意數量的定時器。

first mytimer.h

#include <stdio.h>

#include <stdlib.h>

#include <signal.h>

#include <time.h>

#include <unistd.h>

#include <limits.h>



#define TRUE  1

#define FALSE 0

#define MAX_TIMERS 100 // 最大定時器數

#define VERY_LONG_TIME LONG_MAX // 最長定時數



typedef time_t TIME; // 隱藏TIME的實現

typedef void timer_handler(void *arg); 



volatile TIME time_now,time_set; // now為當前時間,set為當前定時器設定時間



struct sigaction newact,oldact; // 設定sigalrm的處理程式

sigset_t newmask,oldmask; // 設定遮蔽字



struct timer

{

	int inuse; // true if in use

	TIME time; // relative time to wait

	timer_handler *ahandler; // called when the timer has expired

	void *arg; // arguemtn of handler

}timers[MAX_TIMERS];

struct timer *timer_next;



void  timer_init(void); // 初始化計時器

struct timer* timer_declare(TIME,timer_handler*,void*); // 生成一個計時器

void timer_undeclare(struct timer*); // 取消一個計時器

void timer_update(); // 更新計時器陣列,並獲得下一個將要計時的計時器

void timer_out_handler(int signo); // 訊號處理函式

void func(void *arg); // 自定義輸出函式

second mytimer.c

#include "mytimer.h"



static void disable_interrupt(void)  // 關閉中斷

{

	sigemptyset(&newmask);

	sigaddset(&newmask,SIGINT);

	if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) < 0)

		fprintf(stderr,"sigprocmask error\n");

}



static void enable_interrupt(void) // 開啟中斷

{

	if(sigprocmask(SIG_SETMASK,&oldmask,NULL) < 0)

		fprintf(stderr,"sigprocmask error\n");

}



void timer_init(void)

{

	int i;

	disable_interrupt();

	for(i = 0;i<MAX_TIMERS;i++)

		timers[i].inuse = FALSE; // 將計時器陣列中每個計時器inuse狀態設定為未用

	

	sigfillset(&newact.sa_mask); // 在處理訊號時,阻塞所有訊號的遞送

	newact.sa_flags = 0;

	newact.sa_handler = timer_out_handler;

	if(sigaction(SIGALRM,&newact,&oldact) < 0)

	{

		fprintf(stderr,"sigaction error\n");

		enable_interrupt();

		return;

	}

	enable_interrupt();

}



struct timer* timer_declare(TIME time_s,timer_handler *handler,void *arg)

{

	int i;

	disable_interrupt();

	for(i = 0;i<MAX_TIMERS;i++) // 找到第一個未用的計時器

		if(!timers[i].inuse)

			break;

	if(i == MAX_TIMERS) // 所有計時器都已用完

	{

		enable_interrupt();

		return NULL;

	}

	timers[i].time = time_s; // 計時器時間

	timers[i].ahandler = handler; // 計時器處理函式

	timers[i].arg = arg; // 處理函式引數

	

	if(!timer_next) // 當前計時器為唯一計時器

	{

		time_set = time(NULL); // 儲存當前設定時間

		alarm((timer_next = &timers[i])->time); // 開始計時

	}else if(time_s  < (timer_next->time - (time(NULL) - time_set))) // 比較當前計時器和當前正在計時的計時器的時間長度

	{

		timer_update(); // 更新每個計時器的計時

		timer_next = &timers[i]; // 設定新的當前正在計時的計時器

		time_set = time(NULL); // 記錄設定時間

		alarm(timer_next->time); // 開始計時

	}

	timers[i].inuse = TRUE; // 最後再改變inuse防止update干擾

	enable_interrupt();

	return &timers[i];

}



void timer_undeclare(struct timer* t)

{

	disable_interrupt();

	if(!t->inuse)

	{

		enable_interrupt();

		return;

	}

	

	t->inuse = FALSE;

	

	if(t == timer_next) // 如果是當前正在計時的計時器

		timer_update();



	enable_interrupt();

}



void timer_update() // 更新所有計時器時間,並將時間最短的設定為當前正在計時的計時器。

{

	disable_interrupt();

	int i;

	static struct timer timer_last = {FALSE,VERY_LONG_TIME,NULL,NULL};

	timer_next = &timer_last;

	time_now = time(NULL); // 讀取當前時間

	for(i = 0;i<MAX_TIMERS;i++)

	{

		if(timers[i].inuse)

		{

			timers[i].time -= time_now - time_set; // 所有計時更新

			if(timers[i].time < timer_next->time)

				timer_next = &timers[i]; // 更新當前正在計時的計時器

		}

	}

	if(timer_next->inuse) // 如果存在還未發生的定時器

	{

		alarm(timer_next->time);

		time_set = time(NULL);

	}else

		timer_next = NULL;

	enable_interrupt();

}



void timer_out_handler(int signo)

{

	timer_next->ahandler(timer_next->arg);

	timer_next->inuse = FALSE;

	timer_update(); // 尋找下一個執行的定時器

}



void func(void* arg)

{

	char *p = (char*)arg;

	printf("%s\n",p);

}
Contact GitHub API Training Shop Blog About 

© 2017 GitHub, Inc. Terms Privacy Security Status Help 

third main.c

#include "mytimer.c"



int main()

{

	setbuf(stdout,NULL);

	timer_init();

	TIME time = 1;

	timer_declare(time,func,(void*)"hello world");

	time = 3;

	struct timer* t =timer_declare(time,func,(void*)"this is a test");

	time = 5;

	struct timer* m = timer_declare(time,func,(void*)"func(5)");

	timer_undeclare(t);

	while(1)

		pause();

	exit(0);

}

執行結果

具體專案程式碼可見:https://github.com/xiaoHzp/apue/tree/master/ch10/simple10_5


相關推薦

APUE習題10.5implementing software timer

題目:僅使用一個定時器,構造一組函式,使得程序在該單一定時器基礎上可以設定任意數量的定時器。 first mytimer.h #include <stdio.h> #include <stdlib.h> #include <signal

APUE 第三版 習題 10.5

truct spa ive ast discuss bsp timeout 問題 pla 這是書本上的答案: See ‘‘Implementing Software Timers’’ by Don Libes (C Users Journal, vol. 8, no. 11

1047 - C語言程式設計教程(第三版)課後習題10.5

1047 - C語言程式設計教程(第三版)課後習題10.5 時間限制:1秒 記憶體限制:128兆 題目描述 有n人圍成一圈,順序排號。從第1個人開始報數(從1到3報數),凡報到3的人退出圈子,問最後留下的是原來的第幾號的那位。 輸入 初始人數n 輸出 最後一人的初始編號 樣例輸入

1098: C語言程式設計教程(第三版)課後習題10.5---有n人圍成一圈,順序排號。從第1個人開始報數(從1到3報數),凡報到3的人退出圈子,問最後留下的是原來的第幾號的那位。

題目描述 有n人圍成一圈,順序排號。從第1個人開始報數(從1到3報數),凡報到3的人退出圈子,問最後留下的是原來的第幾號的那位。 輸入 初始人數n 輸出 最後一人的初始編號 樣例輸入 3 樣例輸出 2 提示 來源 思路點撥:定義一個數組,陣列下標表示人的編號,若數組裡面的

APUE習題10.6(父子程序同步)

編寫一段程式測試圖10_24中父子程序的同步函式,要求程序建立一個檔案並向檔案寫一個整數0,然後程序呼叫fork,接著父子程序交替增加檔案中的計數器值,每次計數器值增加1,列印是哪一個程序進行來該增加1操作 沒有完全按照題目要求做,直接fork之後01234這樣列印的

習題 7.510個學生,每個學生的資料包括學號、姓名、3門課的成績,從鍵盤輸入10個學生資料,要求打印出3門課的總平均成績,以及最高分的學生的資料。

C++程式設計(第三版)譚浩強 習題7.5 個人設計 習題 7.5 有10個學生,每個學生的資料包括學號、姓名、3門課的成績,從鍵盤輸入10個學生資料,要求打印出3門課的總平均成績,以及最高分的學生的

Centos_6.5Mysql數據庫

服務器 dns服務器 centos6.5 linux mysql 數據庫 1、安裝Mysql數據庫 yum install mysql mysql-server mysql-devel -y 2、啟動Mysql服務 service mysqld start3、設置My

delphi 7 下安裝 indy 10.5.8 教程

沒有 tar png variables 技術分享 移動 二次 rar use 曉不得2013 Delphi XE8 的實際應用。服務對象:非程序員,但期望用delphi提升工作技能。Delphi群:59129236 delphi 7 下安裝

10.5-全棧Java筆記:常見流詳解(三)

java上節我們講到「Java中常用流:緩沖流」,本節我們學習數據流和對象流~ 數據流數據流將“基本數據類型變量”作為數據源,從而允許程序以與機器無關方式從底層輸入輸出流中操作java基本數據類型。 DataInputStream和DataOutputStream提供了可以存取與機器無關的所有Java基礎類

紫書 習題2-5 分數化小數

logs i++ break %d pri max double code bre 1 #include<stdio.h> //基礎版 2 #define MAX 110 3 4 int main(void) 5 { 6 in

IntelliJ IDEA 10.5.1 引用外部Jar包

jar tac att ide dea 引用 int structure nbsp 具體步驟: File -> Project Structure (ctrl + shift + alt + s ) -> Module -> Dependencies -&

2014-10-5 NOIP模擬賽

str 隨機 一個人 保留 有根樹 tree noip 否則 數據規模 祖孫詢問 (tree.pas/c/cpp) 【問題描述】 已知一棵n個節點的有根樹。有m個詢問。每個詢問給出了一對節點的編號x和y,詢問x與y的祖孫關系。 【輸入格式】 輸入第

C/C++算法競賽入門經典Page16 習題1-5 打折

span 博客 保留 double int 保留兩位小數 c++ 小數 pan 題目:一件衣服 95元,若消費滿300元,可打八五折。輸入購買衣服件數,輸出需要支付的金額(單位元),保留兩位小數. 通過分支結構可以判斷是否要打八五折. (1)聲明衣服件數a,需要支付的金額b

Spark Structured Streaming框架(5)進程管理

ntp 框架 manager lis ive term red ogr pan   Structured Streaming提供一些API來管理Streaming對象。用戶可以通過這些API來手動管理已經啟動的Streaming,保證在系統中的Streaming有序執行。

ArcGIS Enterprise 10.5.1 靜默安裝部署記錄(Centos 7.2 minimal版)- 2、安裝Portal for ArcGIS

-a 切換 https stop user 安裝 執行 limits 方式 安裝Portal for ArcGIS 解壓portal安裝包,tar -xzvf Portal_for_ArcGIS_Linux_1051_156440.tar.gz 切換到arcgis賬戶靜

ArcGIS Enterprise 10.5.1 靜默安裝部署記錄(Centos 7.2 minimal版)- 3、安裝 ArcGIS for Server

切換 驗證 裝包 start dap sof 訪問權限 tar 服務 安裝ArcGIS for Server 解壓server安裝包,tar -xzvf ArcGIS_Server_Linux_1051_156429.tar.gz 切換到arcgis賬戶靜默安裝serv

ArcGIS Enterprise 10.5.1 靜默安裝部署記錄(Centos 7.2 minimal版)- 1、安裝前準備

計算機 boot thread connect conf 1.8 div 導入 top 安裝前準備 上傳文件到服務器,x-ftp xshell登陸Centos 檢查機器名 修改機器名為:portal.cloud.local 方法一:零時設置,重啟後失效,

2017-09-10-構建法:現代軟件工程-閱讀筆記

參數 驗證 時間 第二章 軟件企業 功能 模塊 復雜 1.3 第一章 軟件= 程序+軟件工程 程序= 數據結構+算法 軟件企業 = 軟件+商業模式 軟件的特殊性:復雜性、不可見性、易變性、服從性、非連續性。 第二章 2.1單元測試: 2.1.1用VSTS寫單元測試 2.1

0.1 使用w查看系統負載 - 10.2 vmstat命令 - 10.3 top命令 - 10.4 sar命令 - 10.5 nload命令

使用 查看 系統負載 - 10.1 使用w查看系統負載 - 10.2 vmstat命令 - 10.3 top命令 - 10.4 sar命令 - 10.5 nload命令 # 10.1 使用w查看系統負載 ![mark](http://oqxf7c508.bkt.clouddn.com/blo

10.按鍵互斥、阻塞機制

inter lee 多個進程 span 滿足 -1 類型 執行過程 mutex 本節目標: 學習原子操作和互斥信號量,實現互斥機制,同一時刻只能一個應用程序使用驅動程序 學習阻塞和非阻塞操作 當設備被一個程序打開時,存在被另一個程序打開的可能,如果兩個或多個程序同時