Chinaunix首页 | 论坛 | 博客
  • 博客访问: 12237
  • 博文数量: 3
  • 博客积分: 88
  • 博客等级: 民兵
  • 技术积分: 45
  • 用 户 组: 普通用户
  • 注册时间: 2012-08-25 16:39
文章分类
文章存档

2012年(3)

我的朋友

分类: LINUX

2012-08-27 17:20:18

    系统中使用了 System V IPC 方式的进程锁,今天在压测的时候发现在单进程的情况下,依然有很多semop的系统调用,在单进程程的情况下,不存在锁冲突,经过了futex优化,应该不会有semop系统调用的,就仔细研究了一把这个问题,最终发现 System V IPC下的锁是没有经过 futex优化的,不管有没有锁争用,都必然semop的系统调用(加锁和解锁各一次),而经过futex优化的NPTL实现在无冲突的时候是不会导致系统调用的,直接在应用层就解决了,两者在性能上差异较大。

    为了验证这个差异,特意写了个简单的程序做了一个测试,每个测试线程均完成100万次的简单运算,多个线程之间共享一个锁,测试代码如下:

点击(此处)折叠或打开

  1. #include <sys/types.h>
  2. #include <sys/ipc.h>
  3. #include <sys/sem.h>
  4. #include <pthread.h>
  5. #include <semaphore.h>
  6. #include <sys/time.h>
  7. #include <errno.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>

  10. int g_iLockType = -1;
  11. int g_iSemID = -1;

  12. sem_t g_sem;


  13. long g_result = 1;
  14. int createSemMutex(key_t iKey)
  15. {
  16.     #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
  17.     /* union semun is defined by including <sys/sem.h> */
  18.     #else
  19.     /* according to X/OPEN we have to define it ourselves */
  20.     union semun
  21.     {
  22.          int val; /* value for SETVAL */
  23.          struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
  24.          unsigned short *array; /* array for GETALL, SETALL */
  25.                                    /* Linux specific part: */
  26.          struct seminfo *__buf; /* buffer for IPC_INFO */
  27.     };
  28.     #endif

  29.     int iSemID;
  30.     union semun arg;
  31.     u_short array[2] = { 0, 0 };

  32.     //生成信号量集, 包含两个信号量
  33.     if ( (iSemID = semget( iKey, 2, IPC_CREAT | IPC_EXCL | 0666)) != -1 )
  34.     {
  35.         arg.array = &array[0];

  36.         //将所有信号量的值设置为0
  37.         if ( semctl( iSemID, 0, SETALL, arg ) == -1 )
  38.         {
  39.             return -1;
  40.         }
  41.     }
  42.     else
  43.     {
  44.         //信号量已经存在
  45.         if ( errno != EEXIST )
  46.         {
  47.             return -2;
  48.         }

  49.         //连接信号量
  50.         if ( (iSemID = semget( iKey, 2, 0666 )) == -1 )
  51.         {
  52.             return -3;
  53.         }
  54.     }

  55.     return iSemID;
  56. }


  57. int SemMutexLock(int iSemID)
  58. {
  59.     struct sembuf sops[3] = { {0, 0, SEM_UNDO}, {1, 0, SEM_UNDO}, {0, 1, SEM_UNDO} };
  60.     size_t nsops = 3;

  61.     int ret = -1;

  62.     do
  63.     {
  64.         ret=semop(iSemID,&sops[0],nsops);

  65.     } while ((ret == -1) &&(errno==EINTR));

  66.     return ret;
  67. }


  68. int SemMutexUnLock(int iSemID)
  69. {
  70.     struct sembuf sops[1] = { {0, -1, SEM_UNDO} };
  71.     size_t nsops = 1;

  72.     int ret = -1;

  73.     do
  74.     {
  75.         ret=semop(iSemID,&sops[0],nsops);

  76.     } while ((ret == -1) &&(errno==EINTR));

  77.     return ret;
  78. }

  79. void* threadFunc(void* ptr)
  80. {
  81.     int iThread = (long)(ptr);
  82.     printf("thread %d start.\n",iThread);
  83.     if (g_iLockType == 1)
  84.     {
  85.         for (int i = 0 ; i < 1000000 ; ++i)
  86.         {
  87.             if (0 != SemMutexLock(g_iSemID))
  88.             {
  89.                 printf("SemMutexLock fail in thread %d.\n",iThread);
  90.                 return NULL;
  91.             }
  92.             
  93.             for (int j = 0 ; j < 100 ; ++j)
  94.             {
  95.                 int tmp = iThread * i * i * 997 % (i + 7);
  96.                 g_result = iThread * tmp * tmp * 997 % (i + 31);
  97.                 g_result = g_result * 1997 % 91;
  98.             }

  99.             
  100.             if (0 != SemMutexUnLock(g_iSemID))
  101.             {
  102.                 printf("SemMutexUnLock fail in thread %d.\n",iThread);
  103.                 return NULL;
  104.             }            
  105.         }
  106.     }
  107.     else
  108.     {
  109.         for (int i = 0 ; i < 1000000 ; ++i)
  110.         {
  111.             if (0 != sem_wait(&g_sem))
  112.             {
  113.                 printf("sem_wait fail in thread %d.\n",iThread);
  114.                 return NULL;
  115.             }
  116.             
  117.             for (int j = 0 ; j < 100 ; ++j)
  118.             {
  119.                 int tmp = iThread * i * i * 997 % (i + 7);
  120.                 g_result = iThread * tmp * tmp * 997 % (i + 31);
  121.                 g_result = g_result * 1997 % 91;
  122.             }            
  123.     

  124.             if (0 != sem_post(&g_sem))
  125.             {
  126.                 printf("sem_post fail in thread %d.\n",iThread);
  127.                 return NULL;
  128.             }            
  129.         }
  130.     }
  131.     return NULL;
  132. }

  133. int main(int argc, char* argv[])
  134. {
  135.     if (argc != 3)
  136.     {
  137.         printf("usuage:%s lockType threadCount\n",argv[0]);
  138.         return -1;
  139.     }
  140.     
  141.     g_iLockType = atoi(argv[1]);
  142.     int iThreadCount =     atoi(argv[2]);
  143.     printf("locktype=%d ,threadCount=%d\n",g_iLockType,iThreadCount);
  144.     key_t semKey = ftok("sem_mutex_nptl_test",100);
  145.     g_iSemID = createSemMutex(semKey);
  146.     if (g_iSemID < 0)
  147.     {
  148.         printf("createSemMutex fail.return %d\n",g_iSemID);
  149.         return 2;
  150.     }
  151.     
  152.     if (0 != sem_init(&g_sem, 1, 1))
  153.     {
  154.         printf("sem_init fail.\n");
  155.         return 3;        
  156.     }
  157.     
  158.     pthread_t pt[1000];
  159.     
  160.     struct timeval start;
  161.     struct timeval end;
  162.     
  163.     gettimeofday(&start,NULL);
  164.     for (int i = 0 ; i < iThreadCount ; ++i)
  165.     {
  166.         if (0 != pthread_create(pt+i,0,threadFunc,(void*)i))
  167.         {
  168.             printf("create thread %d fail.",i);
  169.             return 3;
  170.         }
  171.     }
  172.     
  173.     for (int i = 0 ; i < iThreadCount ; ++i)
  174.     {
  175.         pthread_join(pt[i],NULL);
  176.     }
  177.     
  178.     gettimeofday(&end,NULL);
  179.     
  180.     printf("time cost = %f ms\n", ((end.tv_sec - start. tv_sec) * 1000000 + (end.tv_usec - start.tv_usec)) / 1000.0);
  181.     return 0;
  182. }

测试结果如下:

锁类型           竞争线程数          耗时(毫秒)

System V IPC          1               9593.426

NPTL                  1               9161.838

System V IPC          2               24292.156

NPTL                  2               21991.775

System V IPC          3               38749.863

NPTL                  3               33610.102

System V IPC          4               50919.030

NPTL                  4               45871.873

System V IPC          5               61978.562

NPTL                  5               56515.495

System V IPC          10              126402.621

NPTL                  10              112752.429

 

    通过strace观察,发现NPTL的锁是没有semop调用的,只有futex_*** 调用,性能上NPTLSystem V IPC 高出10%以上,具体的性能差异与加解锁之间的业务代码的复杂程度相关,建议在使用进程锁的时候,选用NPTL的锁实现替代旧的System V IPC,以提升效率。

阅读(759) | 评论(0) | 转发(0) |
0

上一篇:ostringstream的性能问题

下一篇:没有了

给主人留下些什么吧!~~