Linux下從訊號量看執行緒排程時間
前幾天寫了一篇文章關於Linux下程序排程時間的,本意是想測試下實時效能的,包括中斷響應時間等等,這個可能需要藉助於硬體發出終端來測試,
那片文章是講的是通過傳送訊號給另一個程序,然後測量傳送訊號到進入訊號處理程式之間的時間
訊號只是針對程序來說的,今天講的主要是通過訊號量semaphore來測試一下執行緒間切換的時間
首先看下基礎知識:
1.Linux下的程序和執行緒
linux下執行緒分為使用者級執行緒和核心級執行緒,在核心來看,執行緒和程序是一樣的,本質上沒有區別
核心提供的是建立程序的介面do_fork()。核心提供了兩個系統呼叫clone()和fork(),最終都用不同的引數呼叫do_fork()核內API。當然,要想實現執行緒,沒有核心對多程序(
具體可以參考<<深入理解Linux核心>>第三版,講的非常詳細
2. Linux下的訊號量
訊號量和互斥量一般用來同步訪問某個全域性變數等,防止多個執行緒同時操作一個全域性物件,互斥量mutex就是一把鎖,訊號量還有一個用途就是用來出發另外一個執行緒。訊號量samophore本質上是一個計數器,當其大於0時可以訪問,小於0等於0時不能訪問,相應訪問訊號量的執行緒掛起直到其大於0 。
怎麼由一個執行緒出發另外一個執行緒,先來看看下面兩個函式:
函式sem_post( sem_t *sem )用來增加訊號量的值。當有執行緒阻塞在這個訊號量上時,呼叫這個函式會使其中的一個執行緒不在阻塞,選擇機制同樣是由執行緒的排程策略決定的。
函式sem_wait( sem_t *sem )被用來阻塞當前執行緒直到訊號量sem的值大於0,解除阻塞後將sem的值減一,表明公共資源經使用後減少。函式sem_trywait ( sem_t *sem )是函式sem_wait()的非阻塞版本,它直接將訊號量sem的值減一。
當一個執行緒呼叫sem_wait()函式等待一個訊號量,而這個訊號量不大於0,則這個執行緒就會被核心掛起,此時我們可以用另外一個執行緒呼叫sem_post()函式來增加那個訊號量的值到大於0,那麼剛才那個被阻塞的執行緒就會被執行,這樣就觸發了另外一個執行緒,我們可以用這種辦法來測試Linux下執行緒排程的大概時間,考慮時間精度,我們使用了TSC計數器,該計數器可以提供CPU主頻精度的時間,下面看原始碼
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
int Number = 0;
sem_t sem;
int64_t end = 0;
int64_t start = 0;
float CPU_tick_count_per_second = 3093.059;
#if defined(__i386__)
static __inline__ unsigned long long rdtsc(void)
{
unsigned long long int x;
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
return x; //
}
#elif defined(__x86_64__)
static __inline__ unsigned long long rdtsc(void)
{
unsigned hi, lo;
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}
#endif
static void pthread_fun_1(void)
{
while(1)
{
printf("This is pthread 1.\n");
sleep(1);
sem_post(&sem); //執行緒1傳送訊號量sem,也就是將該訊號量加1
start = rdtsc();
}
pthread_exit(0);
}
static void pthread_fun_2(void)
{
while(1)
{
printf("This is pthread 2.\n");
sem_wait(&sem); //執行緒2等待sem訊號量
end = rdtsc(); //計算從傳送訊號量到執行緒2被重新執行的時間
printf("The time shift between sigpost and sigwait is:%f us\n",(end-start)/CPU_tick_count_per_second);
Number++;
printf("Thread2 add one to Number.\n");
printf("The Number is:%d.\n", Number);
}
pthread_exit(0);
}
int main()
{
pthread_t pt1, pt2;
sem_init(&sem, 0, 1);
int ret = 0;
ret = pthread_create(&pt1, NULL, (void *)pthread_fun_1, NULL);
if(ret)
{
perror("Creat pthread 1 failed.\n");
exit(-1);
}
ret = pthread_create(&pt2, NULL, (void *)pthread_fun_2, NULL);
if(ret)
{
perror("Creat pthread 2 failed.\n");
exit(-1);
}
pthread_join(pt1,NULL);
pthread_join(pt2,NULL);
printf("Main pthread exit.\n");
return 0;
}
x下面是測試的時間結果,在us數量級
參考資料:
2. 深入理解linux核心
3. APUE
閱讀(414) | 評論(0) | 轉發(1) | 給主人留下些什麼吧!~~ 評論熱議