2016-08-09 26 views
2

我在做Linux中的C程序。我有一個主線程連續更新兩個變量的值,其他線程每20毫秒將這些變量值寫入文件。我已經用了睡眠來達到這個時間間隔。示例代碼如下。是否適合在c中使用usleep作爲Timer?

main() 
{ 
. 
. 
. 
. 
. 

pthread_create(...write_file..); /* started another thread by passing a function write_file */ 
while(variable1) 
    { 
    updates value of variables 

    } 

return 0; 
} 


void write_file() 

{ 
. 
. 
. 
. 
fp = fopen("sample.txt" , "a"); 

while(variable2) 
{ 

    fprintf(fp," %d \n", somevariable); 

    usleep(20 * 1000); 

} 

fclose(fp); 
} 

是否適合使用usleep函數實現20毫秒的時間間隔,還是應該使用其他一些方法,如Timer。 這是睡得足夠準確嗎?這種睡眠功能是否會影響主線程?

+0

至少你可以通過'gettimeofday'或'clock_gettime'獲得當前時間,並且只保留下一個活動缺少的時間。 – Marian

+0

C11草案標準n1570:* 5.1.2.4多線程執行和數據競爭4如果其中一個表達式評估修改了某個內存位置,並且另一個讀取或修改了相同的內存位置,則兩個表達式評估發生衝突。 25程序的執行包含一個數據爭用,如果它包含兩個不同線程中的衝突動作,其中至少有一個不是原子的,並且兩個線程都不在 之前。任何這樣的數據競爭都會導致未定義的行爲。* TL; DR:'sleep()'不是同步。 – EOF

回答

1

使用sleep()系列通常會導致非精確的時序,特別是當進程有很多CPU消耗線程並且所需的時間間隔相對較小時(如20ms)時。因此,您不應該假設*sleep()將塊完全調用到指定的時間。對於上面描述的情況,實際的睡眠持續時間可能甚至比指定的長兩倍或更多(假設內核不是實時的)。因此,您應該實施某種補償邏輯,爲隨後的調用調整睡眠持續時間。

更精確(但當然不理想)的方法是使用POSIX計時器。見timer_create()。最精確的計時器是使用SIGEV_SIGNALSIGEV_THREAD_ID通知的計時器(後者僅在Linux系統上)。作爲信號編號,您可以使用其中一個實時信號(SIGRTMINSIGRTMAX),但請注意,pthread實現通常在內部使用這些信號中的幾個,因此您應該仔細選擇實際編號。而且在信號處理器上下文中做某些事情需要額外的關注,因爲不是每個庫函數都可以在這裏安全地使用。你可以找到安全列表here

P.S.還請注意,使用空集調用select()是一種相當便於以亞秒級精度睡眠的方式。

2

睡眠:睡眠()和usleep()函式

現在,讓我先易後難定時調用。對於延遲多秒,你最好的選擇是使用sleep()。對於至少幾十毫秒的延遲(大約10毫秒似乎是最小延遲),usleep()應該工作。這些函數將CPU賦予其他進程(``sleep''),所以CPU時間不會被浪費。有關詳細信息,請參閱睡眠(3)和睡眠(3)的手冊頁。因爲Linux調度程序(對於x86體系結構)通常需要大約50毫秒的時間(取決於處理器和機器的速度以及系統負載),放棄CPU需要很長時間。在將控制權返回給您的過程之前,至少需要大約10-30毫秒。由於這個原因,在很小的延遲時間內,usleep(3)通常比參數中指定的延遲時間多一些,至少大約10 ms。

了nanosleep()

在2.0.x的系列Linux內核的,有一個新的系統調用,了nanosleep()(見了nanosleep(2)手冊頁),它允許你睡覺或短時間延遲(幾微秒或更長)。如果(且僅當)您的進程設置爲軟實時調度(使用sched_setscheduler()),則nanosleep()使用繁忙循環;否則,否則就睡,就像usleep()一樣。

繁忙循環使用udelay()(許多內核驅動程序使用的內部內核函數),循環的長度使用BogoMips值計算(這種繁忙循環的速度是其中一種BogoMips準確測量)。有關它如何工作的詳細信息,請參閱/usr/include/asm/delay.h)。

來源:http://tldp.org/HOWTO/IO-Port-Programming-4.html

嘗試使用nanosleep()代替usleep(),它應該是更準確地爲20ms的時間間隔。