您的位置:首页 > 运维架构 > Linux

Linux下从信号量看线程调度时间

2015-07-29 11:01 696 查看
前几天写了一篇文章关于Linux下进程调度时间的,本意是想测试下实时性能的,包括中断响应时间等等,这个可能需要借助于硬件发出终端来测试,

那片文章是讲的是通过发送信号给另一个进程,然后测量发送信号到进入信号处理程序之间的时间

信号只是针对进程来说的,今天讲的主要是通过信号量semaphore来测试一下线程间切换的时间

首先看下基础知识:

1.Linux下的进程和线程

linux下线程分为用户级线程和内核级线程,在内核来看,线程和进程是一样的,本质上没有区别

内核提供的是创建进程的接口do_fork()。内核提供了两个系统调用clone()和fork(),最终都用不同的参数调用do_fork()核内API。当然,要想实现线程,没有核心对多进程(其实是轻量级进程)共享数据段的支持是不行的,因此,do_fork()提供了很多参数,包括CLONE_VM(共享内存空间)、CLONE_FS(共享文件系统信息)、
CLONE_FILES(共享文件描述符表)、CLONE_SIGHAND(共享信号句柄表)和CLONE_PID(共享进程ID,仅对核内进程,即0号进程有效)。当使用fork系统调用时,内核调用do_fork()不使用任何共享属性,进程拥有独立的运行环境,而使用 pthread_create()来创建线程时,则最终设置了所有这些属性来调用__clone(),而这些参数又全部传给核内的do_fork(),从而创建的“进程”拥有共享的运行环境,只有栈是独立的,由__clone()传入。

具体可以参考<<深入理解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

#include

#include

#include

#include

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数量级



参考资料:

1. http://hi.baidu.com/feng2211/item/901579caaad0c40bad092f45

2. 深入理解linux内核

3. APUE

from: http://blog.chinaunix.net/uid-25002135-id-3488560.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: