免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123
最近访问板块 发新帖
楼主: ypxing
打印 上一主题 下一主题

[函数] [原创]reentrant函数与thread safe函数浅析 [复制链接]

论坛徽章:
0
21 [报告]
发表于 2007-08-09 10:29 |只看该作者
在多线程条件下,
理论上,将malloc放入signal的handler也是会出问题的,
锁是不行的,会死锁

原帖由 bluster 于 2007-8-9 10:08 发表

多线程条件下,signal的handler有可能在一个单独的线程中执行,如果这样那么malloc用锁保护就够了。

论坛徽章:
0
22 [报告]
发表于 2007-08-09 16:22 |只看该作者
试图测试malloc不可重入性的代码如下:


  1. main.c
  2. /*这是主程序,用来调用malloc*/

  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <signal.h>
  6. #include <string.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>

  9. void setUnblock()
  10. {
  11.   sigset_t sigset;
  12.   sigemptyset(&sigset);
  13.   sigprocmask(SIG_SETMASK, &sigset, NULL);
  14.       
  15. }


  16. void usr1Handler (int signal_number)        /*处理SIGUSR1信号*/
  17. {
  18.   setUnblock(); /*使得SIGUSR1可以被嵌套*/
  19.   free((int*)malloc(sizeof(int)*1000));
  20.   //printf("enter handler\n");
  21.   //getchar();
  22. }

  23. int main ()
  24. {
  25.   int *pi;
  26.   struct sigaction sa;
  27.   
  28.   memset(&sa, 0, sizeof(sa));
  29.   sa.sa_handler = &usr1Handler;
  30.   sigaction(SIGUSR1, &sa, NULL);

  31.   pause();
  32.   
  33.   return 0;
  34. }


复制代码


  1. kill.c

  2. /*这个是用来发送SIGUSR1信号的*/
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <string.h>

  6. int main(int argc,char *argv[])
  7. {
  8.   int i;
  9.   char killstr[30]="kill -USR1 ";
  10.   if (argc == 2)
  11.   {
  12.     strcat(killstr, argv[1]);
  13.   }
  14.    for (i=0; i<3; i++)
  15.   {
  16.    fork();        /*这样会有8个进程同时发送*/
  17.   }
  18.   
  19.   while(1)
  20.   {
  21.     system(killstr);
  22.   }
  23.   
  24.   return 0;
  25. }

复制代码


验证方法是:
1. 编译main.c 和kill.c
gcc main.c -o main
gcc kill.c -o kill

2. 运行./main
并在另外一个终端运行ps -A|grep main查找出该进程的进程号为pid

3. 运行./kill pid (此处pid为第二步查到的pid)

运行了很长时间,也没有crash
请大家看看我的程序,讨论一个测试方案出来

原帖由 ypxing 于 2007-8-8 23:05 发表
这两天写了一个测试程序来验证malloc的不可重入性
但是malloc一直没有crash,有点郁闷

过段时间把自己的测试代码贴出来,让大家来帮忙看看

论坛徽章:
0
23 [报告]
发表于 2007-08-09 17:36 |只看该作者
原帖由 ypxing 于 2007-8-9 16:22 发表
试图测试malloc不可重入性的代码如下:


main.c
/*这是主程序,用来调用malloc*/

#include
#include
#include
#include
#include
#include

void setUnblock()
{
  sigset_t sigset;
  s ...

我估计是因为现在的malloc是线程安全的原因所以不会crash但是死锁。
我在debian上面的一个测试代码,会死锁,top一下会发现进程状态总是sleep

  1. #include <sys/types.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <signal.h>
  5. #include <unistd.h>

  6. #if        0
  7. #define        PRINT(a)        do {        \
  8.         printf a;                \
  9.         fflush(stdout);                \
  10. }while(0)
  11. #else
  12. #define        PRINT(a)
  13. #endif

  14. static void
  15. run_malloc(void)
  16. {
  17.         void        *mem[8];
  18.         int        sz;
  19.         int        i;

  20.         for (i = 0; i < (sizeof(mem)/sizeof(mem[0])); i++) {
  21.                 sz = random() % (1024 * 1024);
  22.                 if (sz <= 0)
  23.                         sz = 1024;
  24.                 mem[i] = malloc(sz);
  25.                 if (mem == NULL) {
  26.                         PRINT (("[%d] malloc null...\n", i));
  27.                         exit(-1);
  28.                 }
  29.                 PRINT(("%d\n", i));
  30.                 snprintf(mem[i], sz, "this is a test...");
  31.         }

  32.         for (--i; i >= 0; i--) {
  33.                 free(mem[i]);
  34.         }
  35. }

  36. static void
  37. sighandler(int signo)
  38. {
  39.         static void *mem = NULL;

  40.         PRINT ((".\n"));
  41.         if (mem == NULL) {
  42.                 mem = malloc(1024);
  43.         } else {
  44.                 free(mem);
  45.                 mem = NULL;
  46.         }
  47. }

  48. static void
  49. malloc_loop(void)
  50. {

  51.         for (;;)
  52.                 run_malloc();
  53. }

  54. static void
  55. signal_loop(pid_t child)
  56. {
  57.         int        usec;

  58.         for (;;) {
  59.                 kill(child, SIGUSR1);
  60.                 usec = ((unsigned int)random()) % 10;
  61.                 usleep(usec);
  62.         }
  63. }

  64. int
  65. main(int argc, char **argv)
  66. {
  67.         pid_t        child;

  68.         if ((child = fork()) < 0) {
  69.                 perror("fork()");
  70.                 exit(-1);
  71.         } else if (child == 0) {
  72.                 /* child */
  73.                 if (signal(SIGUSR1, sighandler) < 0) {
  74.                         perror("signal");
  75.                         exit(-1);
  76.                 }
  77.                 malloc_loop();
  78.         } else {
  79.                 /* parent */
  80.                 signal_loop(child);
  81.         }

  82.         return        0;
  83. }


复制代码

论坛徽章:
0
24 [报告]
发表于 2007-08-10 11:45 |只看该作者

回复 #1 ypxing 的帖子

谢谢楼主讲解.收藏先

论坛徽章:
0
25 [报告]
发表于 2008-02-23 12:12 |只看该作者

回复 #1 ypxing 的帖子

顶...

论坛徽章:
0
26 [报告]
发表于 2008-02-23 19:46 |只看该作者
不知道这个理解对不对:
thread-safe和reentrant的区别:在发生中断时,高优先级代码抢占,此时若低优先级代码持有锁,则高优先级代码会一直等待锁打开,但是低优先级代码失去了调度机会,于是造成死锁。thread-safe不考虑这种情况,但是reentrant需要。

实现reentrant的几种方法:
1不使用临界区,把原先的全局/静态变量变成函数参数,由函数调用者维护。优点是实现简单,缺点是函数功能的封装性可能会受到影响。
2在进入临界区之前,关中断(屏蔽信号)。优点是实现简单,缺点是影响实时性能,在多核机器上可能引起瓶颈(几个核等待一个核释放信号量)。
3尝试加锁,无法加锁返回一个出错值,而不是一直等待下去。缺点是出错处理比较麻烦
4为一组临界量开启一个专门的线程进行处理。优点是可以对临界区的访问按优先级排序,以及其它可扩展操作,缺点是性能受到IPC的影响。
5使用lock-free结构取代锁。缺点是lock-free算法很多都需要memory-copy,影响效率。

论坛徽章:
0
27 [报告]
发表于 2011-04-24 02:12 |只看该作者
学习了,谢谢!

论坛徽章:
0
28 [报告]
发表于 2011-04-26 02:00 |只看该作者
嗯,学习了,谢谢分享。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP