文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何分析Linux多线程可重入函数

2023-06-28 12:47

关注

如何分析Linux多线程可重入函数,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

Reentrant和Thread-safe

在单线程程序中,整个程序都是顺序执行的,一个函数在同一时刻只能被一个函数调用,但在多线程中,由于并发性,一个函数可能同时被多个函数调用,此时这个函数就成了临界资源,很容易造成调用函数处理结果的相互影响,如果一个函数在多线程并发的环境中每次被调用产生的结果是不确定的,我们就说这个函数是”不可重入的”/”线程不安全”的。为了解决这个问题,POSIX多线程库提出了一种机制,用来解决多线程环境中的线程数据私有化问题,这套机制的主要思想是利用同步和互斥维护一个同名不同值的表,这个表会维护每个线程自己的资源地址,表面上是同一个变量,实质上这个变量在不同的线程中的地址是不一样,这样就保证了每个线程其实都在使用自己的资源,实现了”thread-safe”。

其实,随着多线程程序的逐渐流行,除了这种利用系统机制保护线程私有数据的方法,还有一部分人重新编写了一些多线程库函数,这些函数的主要特点就是实现了算法和数据的分离,函数内部只负责实现算法,需要的数据由线程传入,这样就保证了函数的多线程安全,

eg

 char *asctime(const struct tm *tm); char *asctime_r(const struct tm *tm, char *buf);  //这个就是asctime的thread-safe版,有_r后缀

但由于接口不同,完全重写的函数推广尚需时日。

当下用的更多的是使用_REENTRANT来在原来的函数的基础上改造,如果编译的时候定义了这个宏,相关的库函数就会被编译成”thread-safe”的版本。

模型

如果要查看这些函数的man手册,可以安装相关的man手册

 pthread_key_t key           //创建用于保护线程私有资源的 keypthread_once_t once_key     //创建用于初始化key的once_key,要求用PTHREAD_INIT_ONCE来赋值,否则结果不确定  pthread_key_create()        //创建 keypthread_once()              //初始化 keypthread_getspedifc()        //从key表中获得线程私有资源的地址  pthread_setspedifc()        //将线程私有资源的地址放到key中...

例子

表面上每个函数调用了reverse()都会得到rev的地址,其实这个rev地址在不同的线程中并不相同,一旦一个线程调用了reverse()函数,函数首先会到key标识的表中去搜索这个线程以前是否调用过这个函数,如果调用过,就将表中属于这个线程的rev地址返回,如果没有,就分配rev,并将该线程和它的专属rev地址注册到表中,这样就把reverse()打造成了一个可重入的函数。

 #include #include #include #include  pthread_key_t key; pthread_once_t once_key=PTHREAD_ONCE_INIT;  #ifdef _REENTRANT void myDestructor(void*p){     free(p); } void myCreateKey(void){    //创建key     pthread_key_create(&key,myDestructor); } #endif  char* reverse(char* buf,int len){ #ifdef _REENTRANT     //初始化key     pthread_once(&once_key,myCreateKey);  //从key中获取一个thread-specific的数据     char* rev=(char*)pthread_getspecific(key);     if(NULL==rev){         rev=(char*)malloc(len+1);        //将thread-specific的数据放到key中         pthread_setspecific(key,rev);     } #else     static char rev[100]; #endif     bzero(rev,sizeof(rev));    //翻转buf     while(len--)         rev[len]=*buf++;     return rev; } void* fcn1(void* p){     while(1){         char buf[100]="123456789";         printf("[%lu]:%s\n",pthread_self(),buf);         char* rev=reverse(buf,strlen(buf));         sleep(1);         printf("[%lu]:%s\n",pthread_self(),rev);     }  } void* fcn2(void* p){     while(1){         char buf[100]="abcdef";         printf("[%lu]:%s\n",pthread_self(),buf);                 char* rev=reverse(buf,strlen(buf));         sleep(2);                 printf("[%lu]:%s\n",pthread_self(),rev);      } }int main(int argc, const char *argv[]){     pthread_t tid[4];     pthread_create(&tid[0],NULL,fcn1,NULL);     pthread_create(&tid[1],NULL,fcn2,NULL);     pause();         return 0; }

看完上述内容,你们掌握如何分析Linux多线程可重入函数的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注编程网行业资讯频道,感谢各位的阅读!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-人工智能
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯