本回將嘗試在Linux環境下能否在系統監視器中畫出一個正弦曲線。本人環境為Ubuntu 11.04.
基本思想還是和Windows下面的相同,更換系統調用,便可以實現功能的遷移。
#include <time.h>#include <sys/time.h>#include <unistd.h>#include<stdlib.h>#include<math.h>#define DWORD unsigned long#define UINT64 unsigned long longconst double SPLIT = 0.01;const int COUNT = 200;const double PI = 3.14159265;const int INTERVAL = 300;int main(int argc, char* argv[] ){struct timeval tms;DWORD busySpan[COUNT];DWORD idleSpan[COUNT];int half = INTERVAL/2, i;double radian = 0.0;for(i = 0; i < COUNT; ++i){busySpan[i] = (DWORD)(half + (sin(PI * radian) * half));idleSpan[i] = INTERVAL - busySpan[i];radian += SPLIT;}clock_t startTime = 0;int j = 0;while(1){j = j % COUNT;timerclear(&tms);gettimeofday(&tms,NULL);UINT64 startTime = tms.tv_usec;while(1)//clock返回該進程從啟動到現在經曆的毫秒數(千分之一秒){timerclear(&tms);gettimeofday(&tms,NULL);UINT64 nowTime = tms.tv_usec;if((nowTime - startTime)/1000 > busySpan[j])break;} if(usleep(idleSpan[j]*1000)) //精確到微秒(百萬分之一秒)的函數 exit(-1);j++;}return 0;}
gettimeofday()函數用來取得目前時間(微秒,百萬分之一秒)。並通過參數傳遞給結構體timeval類型的tms。
int gettimeofday(struct timeval *tv, struct timezone *tz);
tz用來擷取時區資訊。不做介紹。
結構體timeval的定義為:
struct timeval
{
time_t tv_sec; //seconds
suseconds_t tv_usec; //microseconds
};
tz如果是NULL的話將不傳遞時區資訊。tv提供秒為單位的和微妙為單位的從Epoch開始的計數。
結構體timeval的域為類型long的域。
此函數返回0,表示成功,-1表示失敗。
Windows中,GetTickCount返回的是從系統啟動到現在的毫秒。
int usleep(useconds_t usec);
定義在標頭檔unistd.h中。它使當前進程掛起至少usec微秒(百萬分之一秒).睡眠時間可能會被任意系統活動或進程切換開銷或系統計時器的精確度而輕微延遲。成功時返回0,錯誤時返回-1.
或者使用clock()來得到系統時間也是可以的。它返回從進程啟動到現在經曆的時間,單位是毫秒(千分之一秒)。定義在標頭檔time.h下.
clock_t clock(void);
相應代碼如下。
#include <time.h>#include <sys/time.h>#include <unistd.h>#include<stdlib.h>#include<math.h>#define DWORD unsigned long#define UINT64 unsigned long longconst double SPLIT = 0.01;const int COUNT = 200;const double PI = 3.14159265;const int INTERVAL = 300;int main(int argc, char* argv[] ){struct timeval tms;DWORD busySpan[COUNT];DWORD idleSpan[COUNT];int half = INTERVAL/2, i;double radian = 0.0;for(i = 0; i < COUNT; ++i){busySpan[i] = (DWORD)(half + (sin(PI * radian) * half));idleSpan[i] = INTERVAL - busySpan[i];radian += SPLIT;}clock_t startTime = 0;int j = 0;while(1){j = j % COUNT;timerclear(&tms);gettimeofday(&tms,NULL);clock_t startTime = clock();while((clock()-startTime) <= busySpan[j])//clock返回該進程從啟動到現在經曆的毫秒數(千分之一秒); if(usleep(idleSpan[j]*1000)) //精確到微秒(百萬分之一秒)的函數 exit(-1);j++;}return 0;}
但對於多核CPU,如何限制進程在一個CPU上運行呢?
如何察看某個進程在哪個CPU上運行:
在控制台中輸入:
#top -d 1
之後按下f.進入top Current Fields設定頁面:
選中:j: P = Last used cpu (SMP)
則多了一項:P 顯示此進程使用哪個CPU。
經過實驗發現:同一個進程,在不同時刻,會使用不同CPU Core.這應該是Linux Kernel SMP處理的。
本程式通過這個方法查看,將會在多個CPU上運行。
想要讓它在一個CPU上執行,可以這樣做:
1.下載包schedtool.
在控制台中輸入:sudo apt-get install schedtool,然後輸入你的密碼。
schedtool是Linux下用來查詢或設定CPU狀態的工具。通過不同的參數可以查看或設定不同的屬性。
[-0|-N] [-1|-F] [-2|-R] [-3|-B] [-4|-I] [-5|-D] [-M policy] [-a affinity] [-p prio] [-n nice_level] [-e command [arg ...]] [-r] [-v] [-h]
我們這裡要用到的是 -a和-e。其他可以參考這裡:
http://linux.die.net/man/8/schedtool
-a用來設定進程在哪個CPU上運行。-a的參數為:
0x1 表示只運行在CPU0(00000001)
0x2 表示只運行在CPU1(00000010)
0x4表示紫雲行在CPU2(00000100)
0x8表示只運行在CPU3(00001000)
etc.
或者,多CPU運行可以這樣表示,
0x7表示可以運行在CPU0,1,2 (00000111)
0x5表示可運行在CPU0,2 (00000101)
以此類推。
-e用來通過指定的參數來執行命令。後面的參數為控制台命令。
在Linux下,如何確認是多核或多CPU:
#cat /proc/cpuinfo
如果有多個類似以下的項目,則為多核或多CPU:
processor : 0
......
processor : 1
在編譯後,我們執行命令:sched -a 0x1 -e ./案頭/sin
可以通過上面介紹的方法查看進程sin是否在同一個CPU上運行。
然後就可以通過系統監視器查看運行結果啦!
運行結果(橙色線):
還有一段Python的代碼,運行是與上面類似的,這個來自於網上^_^:
#!/usr/bin/env pythonimport itertools, math, time, systime_period = float(sys.argv[1]) if len(sys.argv) > 1 else 30 # secondstime_slice = float(sys.argv[2]) if len(sys.argv) > 2 else 0.04 # secondsN = int(time_period / time_slice)for i in itertools.cycle(range(N)): busy_time = time_slice / 2 * (math.sin(2*math.pi*i/N) + 1) t = time.clock() + busy_time while t > time.clock(): pass time.sleep(time_slice - busy_time);
在控制台下輸入命令:sched -a 0x1 -e python ./案頭/sin_p.py(此處寫你源檔案的路徑).即可!