良许Linux教程网 干货合集 Linux多线程可重入函数

Linux多线程可重入函数

本篇文章为大家分享一下Linux多线程可重入函数的相关知识,本文实操记录、绝无水文,如果错误或者遗漏欢迎大家指正。

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系统中多线程可重入函数的相关知识分享完毕,欢迎大家在评论区留言/

以上就是良许教程网为各位朋友分享的Linux系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你!

137e00002230ad9f26e78-265x300

本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部