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

前几天写了一篇文章关于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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值