2021-2022-1-diocs-定時器及時鍾服務學習筆記


20191205 2021-2022-1-diocs-定時器及時鍾服務(第八周學習筆記)

一、任務詳情

自學教材第5章,提交學習筆記(10分)

知識點歸納以及自己最有收獲的內容 (3分)

問題與解決思路(2分)

實踐內容與截圖,代碼鏈接(3分)

...(知識的結構化,知識的完整性等,提交markdown文檔,使用openeuler系統等)(2分)

 

二、教材內容歸納整理

本章討論了定時器和定時器服務;介紹了硬件定時器的原理和基於Intel x86PC 中的硬件定時器;講解了 CPU操作和中斷處理;描述了Linux中與定時器相關的系統調用、庫函數和定時器服務命令;探討了進程間隔定時器、定時器生成的信號,並通過示例演示了進程間隔定時器。編程項目的目的是要在一個多任務處理系統中實現定時器、定時器中斷和間隔定時器。多任務處理系統作為—個Linux進程運行,該系統是 Linux進程內並發任務的一一個虛擬 CPULinux 進程的實時模式間隔定時器被設計為定期生成SIGALRM信號,充當虛擬CPU 的定時器中斷,虛擬CPU使用SIGALRM信號捕捉器作為定時器的中斷處理程序。該項目可讓讀進程通過定時器隊列實現任務間隔定時器,還可讓讀進程使用Linux 信號掩碼來實現臨界區,以防止各項任務和中斷處理程序之間出現競態條件。

 

思維導圖

 

一、知識點總結

1.個人計算機定時器

(1)實時時鍾(RTC):RTC由一個小型備用電池供電。即使在個人計算機關機時,它也能連續運行。它用於實時提供時間和日期信息。當Linux啟動時,它使用RTC更新系統時間變量,以與當前時間保持一致。在所有類Unix 系統中,時間變量是一個長整數,包含從197011日起經過的秒數。

2)可編程間隔定時器(PIT)(Wang 2015)∶PIT是與CPU分離的一個硬件定時器。可對它進行編程,以提供以毫秒為單位的定時器刻度。在所有I/O設備中,PIT 可以最高優先級 IRQ0中斷。PIT定時器中斷由Linux 內核的定時器中斷處理程序來處理,為系統操作提供基本的定時單元,例如進程調度、進程間隔定時器和其他許多定時事件。

3)多核CPU 中的本地定時器(Intel 1997;Wang 2015))∶在多核CPU中,每個核都是一個獨立的處理器,它有自己的本地定時器,由 CPU時鍾驅動。

4)高分辨率定時器∶大多數電腦都有一個時間戳定時器(TSC)由系統時鍾驅動。它的內容可通過64 TSC寄存器讀取。由於不同系統主板的時鍾頻率可能不同,TSC不適合作為實時設備,但它可提供納秒級的定時器分辨率。—些高端個人計算機可能還配備有專用高速定時器,以提供納秒級定時器分辨率。

2.CPU操作

每個CPU都有一個程序計數器(PC),也稱為指令指針(IP),以及一個標志或狀態寄存器(SR)、一個堆棧指針(SP)和幾個通用寄存器,當 PC指向內存中要執行的下一條指令時,SR包含 CPU 的當前狀態,如操作模式、中斷掩碼和條件碼,SP指向當前堆棧棧頂。

while (power-on){

(1).  fetch instruction:load*PC as instruction,increment PC to point to the

next instruction in memory;

(2).  decode instruction: interpret the instruction's operation code and

generate operandis;

(3).  execute instruction: perform operation on operands,write results to

memory if needed; execution may use the stack,implicitly change PC, etC.

(4) .  check for pending interrupts; may handle interrupts;

}

3.中斷處理

外部設備(如定時器)的中斷被饋送到中斷控制器的預定義輸入行(Intel 1990;Wang 2015),按優先級對中斷輸入排序,並將具有最高優先級的中斷作為中斷請求(IRQ)路由到 CPU

對於每個中斷,可以編程中斷控制器以生成一個唯一編號,叫作中斷向量,標識中斷源。在獲取中斷向量號后,CPU用它作為內存中中斷向量表AMD64 20I1)中的條目索引,條目包含一個指向中斷處理程序入口地址的指針來實際處理中斷。當中斷處理結束時,CPU恢復指令的正常執行。

4.間隔定時器

間隔定時器由 setitimer()系統調用創建。getitimer()系統調用返回間隔定時器的狀態。

int getitimer(int which, struct itimerval *curr_value);

int setitimer(int which,const struct itimerval *new_value,

struct itimerva1 *old_value);

各間隔定時器在參數 which指定的不同時間域中工作。當間隔定時器定時到期時,會向進程發送一個信號,並將定時器重置為指定的間隔值(如果是非零數)。一個信號就是發送給某個進程進行處理的一個數字(131)。有3類間隔定時器,分別是:

1ITIMER_REAL:實時減少,在到期時生成一個SIGALRM14)信號。

2ITIMER_VIRTUAL:僅當進程在用戶模式下執行時減少,在到期時生成一個SIGVTALRM26)信號。

3ITIMER PROF:當進程正在用戶模式和系統(內核)模式下執行時減少。這類間隔

5.間隔定時器

定時器計時,並向進程生成一個信號。操作系統內核不必使用額外的數據結構來處理進程的VIRTUAL PROF定時器。但是,REAL模式間隔定時器各不相同,因為無論進程是否正在執行,它們都必須由定時器中斷處理程序來更新。因此,操作系統內核必須使用額外的數據結構來處理進程的 REAL 模式定時器,並在定時器到期或被取消時采取措施。在大多數操作系統內核中,使用的數據結構都是定時器隊列。我們將在本章末尾解釋編程項目中的定時器隊列。

 

二、最有收獲的內容

Gettimeofday-settimeofday系統調用

#include <sys/time.h>


int gettimeofday(struct timeval*tv,struct timezone *tz);


int settimeofday(const struct timeval *tv,const struct timezone *tz);

這些是對Linux 內核的系統調用。第一個參數 tv指向一個timeval結構體。

struct timeval {
time_t   tv_BeC;    /* secondg */tV_ugec;
suseConds_t   tv_usec    /* microseconds * /);

第二個參數 timezone已過期,應設置為NULLgettimeofday()函數用於返回當前時間(當前秒的秒和微秒)。settimeofday(函數用於設置當前時間。在 Unix/Linux中,時間表示自19701100∶00∶00起經過的秒數。它可以通過庫函數 ctime&time)轉換為日歷形式。

time系統調用

time_t time(time_t *t)

以秒為單位返回當前時間。如果參數t不是NULL,還會將時間存儲在t指向的內存中。time 系統調用具有一定的局限性,只提供以秒為單位的分辨率,而不是以微秒為單位。

times系統調用

clock_t times(struct tms *buf);

可用於獲取某進程的具體執行時間。它將進程時間存儲在 struct tms buf 中,即

struct tms{

clock t tms utime;  // user mode time

      clock_t tms_stime; // system mode time

clock__t tms_cutime; // user time of children

clock_t tms_cstime;   // system time of children

);

以時鍾計時單元報告所有時間。這可以為分析某個正在執行的進程提供信息,包括其子進程的時間

timedata命令

date:打印或設置系統日期和時間。

time:報告進程在用戶模式和系統模式下的執行時間和總時間。

hwclock:查詢並設置硬件時鍾(RTC),也可以通過 BIOS來完成。

 

三、問題與解決思路(解決思路是基於OpenEuler系統下解決的)

問題:Linux里如何用C編程實現gettimeofday系統調用

解決思路:

編寫C代碼實現gettimeofday()系統調用來獲取系統時間

#include <stdio.h>

#include <stdlib.h>

#include <sys/time.h>

struct timeval t;

int main()

{

gettimeofday(&t,NULL);

printf("sec=%ld usec=%d\n", t.tv_sec, t.tv_usec);

printf((char *)ctime(&t.tv_sec));

}

運行截圖:

問題:Linux里如何用C編程實現settimeofday系統調用

解決思路:

編寫C代碼實現time系統調用

#include<stdio.h>

#include<stdio.h>

#include<time.h>

time_t start,end;

int main()

{

int i;

start=time(NULL);

printf("start=%ld\n",start);

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

end=time(NULL);

printf("end =%ld time=%ld\n",end,end-start);

}

運行截圖:

 

四、實踐內容(截圖、代碼鏈接)

Linux多任務編程——多線程實現多任務

(1)線程號的比較

所需頭文件:

#include

int pthread_equal(pthread_t t1, pthread_t t2);

功能:

判斷線程號 t1 t2 是否相等。為了方便移植,盡量使用函數來比較線程 ID

參數:

t1t2:待判斷的線程號。

返回值:

相等:  非 0

不相等:0

代碼鏈接:

https://gitee.com/two_thousand_and_thirteen/codes/mgadw1n0ft5k4lqr7oscj41

運行截圖:

(2)線程的創建

所需頭文件:

#include

int pthread_create( pthread_t *thread,

const pthread_attr_t *attr,

void *(*start_routine)(void *),

void *arg );

功能:

創建一個線程。

參數:

thread:線程標識符地址。

attr:線程屬性結構體地址,通常設置為 NULL

start_routine:線程函數的入口地址。

arg:傳給線程函數的參數。

返回值:

成功:0

失敗:非 0

pthread_create() 創建的線程從指定的回調函數開始運行,該函數運行完后,該線程也就退出了。線程依賴進程存在的,共享進程的資源,如果創建線程的進程結束了,線程也就結束了。

代碼鏈接:

https://gitee.com/two_thousand_and_thirteen/codes/7p0wx4gn6hjorezd53avm52

運行截圖:

(3)回收線程資源

所需頭文件:

#include

int pthread_join(pthread_t thread, void **retval);

功能:

等待線程結束(此函數會阻塞),並回收線程資源,類似進程的 wait() 函數。如果線程已經結束,那么該函數會立即返回。

參數:

thread:被等待的線程號。

retval:用來存儲線程退出狀態的指針的地址。

返回值:

成功:0

失敗:非 0

代碼鏈接:

https://gitee.com/two_thousand_and_thirteen/codes/91rse72fjcdvki8qzlp3g73

運行結果:

(4)線程退出

在進程中我們可以調用 exit() 函數或 _exit() 函數來結束進程,在一個線程中我們可以通過 pthread_exit() 在不終止整個進程的情況下停止它的控制流。

所需頭文件:

#include

void pthread_exit(void *retval);

功能:

退出調用線程。一個進程中的多個線程是共享該進程的數據段,因此,通常線程退出后所占用的資源並不會釋放。

參數:

retval:存儲線程退出狀態的指針。

返回值:

代碼鏈接:

https://gitee.com/two_thousand_and_thirteen/codes/tcjuyro2i45mbhkzfgs0716

運行結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM