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           //创建用于保护线程私有资源的key
pthread_once_t once_key     //创建用于初始化key的once_key,要求用PTHREAD_INIT_ONCE来赋值,否则结果不确定
pthread_key_create()        //创建key
pthread_once()              //初始化key
pthread_getspedifc()        //从key表中获得线程私有资源的地址
pthread_setspedifc()        //将线程私有资源的地址放到key中
...

例子

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

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>
pthread_key_t key;
pthread_once_t once_key=PTHREAD_ONCE_INIT;
#ifdef _REENTRANT
void myDestructor(void*p){free(p);
}
void myCreateKey(void){//创建keypthread_key_create(&key,myDestructor);
}
#endifchar* reverse(char* buf,int len){
#ifdef _REENTRANT//初始化keypthread_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);}
#elsestatic char rev[100];
#endifbzero(rev,sizeof(rev));//翻转bufwhile(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;
}

转载于:https://www.cnblogs.com/xiaojiang1025/p/6020822.html

Linux 多线程可重入函数相关推荐

  1. linux中可重入函数、不可重入函数

    1.结论:可重入函数必然是线程安全函数和异步信号安全函数: 线程安全函数不一定是可重入函数. 例如:strtok是既不可重入的,也不是线程安全的:加锁的strtok不是可重入的,但线程安全. 2.不可 ...

  2. 【Linux系统编程】可重入和不可重入函数

    00. 目录 文章目录 00. 目录 01. 不可重入函数 02. 可重入函数 03. 判断条件 04. Linux常用可重入函数 05. 附录 01. 不可重入函数 在实时系统的设计中,经常会出现多 ...

  3. Linux可重入函数

    1.可重入函数 可重入函数指的是可以被中断的函数.也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误:而不可重入的函数由于使用了一些系统资源, ...

  4. Linux中的可重入函数和不可重入函数

    可重入函数 可重入函数(即可以被中断的函数)可以被一个以上的任务调用,而不担心数据破坏.可重入函数在任何时候都可以被中断,而一段时间之后又可以恢复运行,而相应的数据不会破坏或者丢失. 可重入函数使用的 ...

  5. 【Linux系统编程】可重入函数和不可重入函数

    在实时系统的设计中,经常会出现多个任务调用同一个函数的情况.如果有一个函数不幸被设计成为这样:那么不同任务调用这个函数时可能修改其他任务调用这个函数的数据,从而导致不可预料的后果.这样的函数是不安全的 ...

  6. Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号

    首先区分一下Linux信号跟进程间通信中的信号量,它们的关系就犹如老婆跟老婆饼一样,没有一毛钱的关系. 信号的概念 信号的概念:信号是进程之间事件异步通知的一种方式,属于软中断.比如:红绿灯是一种信号 ...

  7. [ Linux ] 可重入函数,volatile 关键字,SIGCHLD信号

    目录 1.可重入函数 2.volatile 2.1从信号角度理解volatile的作用 2.2volatile的作用 3.SIGCHLD信号 3.1SIGCHLD信号的验证 1.可重入函数 在数据结构 ...

  8. Linux | 可重入函数 | volatile | SIGCHLD信号

    文章目录 可重入函数 可重入与线程安全 volatile volatile和const同时修饰变量 SIGCHLD信号 可重入函数 当一个函数可以被两个执行流调用,我们称该函数具有重入特征 如果一个函 ...

  9. Linux信号编程实践(二) 信号发送函数和可重入函数

    在早期的UNIX中信号是不可靠的,不可靠在这里指的是:信号可能丢失,一个信号发生了,但进程却可能一直不知道这一点. 现在Linux 在SIGRTMIN实时信号之前的都叫不可靠信号,这里的不可靠主要是不 ...

最新文章

  1. java自己实现读写锁_关于读写锁算法的Java实现及思考
  2. 小学生学python-小学生都学Python了,你还不知道如何开始
  3. 从svn下载项目后build path为灰色
  4. php定时爬虫,thinkphp5使用workerman定时器定时爬取站点内容的代码
  5. scrapy 动态IP、随机UA、验证码
  6. 交叉熵(cross_entropy)作为损失函数在神经网络中的作用
  7. ios-新浪微博-下拉刷新获取最新的消息(解决消息重复的问题)(五)
  8. 解决C# 7.2中的结构体性能问题
  9. Java与C#个人之比较
  10. docker导入与导出容器
  11. uCOS-II在51单片机上的移植
  12. py2topy3+cmd 命令
  13. [转载]VC6中的文件后缀
  14. Redis常见的5种不同的数据类型详解
  15. 宝塔/Linux下自动更新maccms到github原版的最新版
  16. java:求解二元一次方程(小程序)
  17. 微信小程序开发相关资料
  18. muduo学习笔记:net部分之实现TCP网络编程库-TcpClient
  19. 我为什么反对用各类框架
  20. java计算机毕业设计基于web的老年公寓管理源码+数据库+系统+lw文档+mybatis+运行部署

热门文章

  1. Luogu 3066 [USACO12DEC]逃跑的BarnRunning Away From…
  2. 面试题:二叉树中和为某一路径
  3. bzoj2878 [Noi2012]迷失游乐园——概率期望DP
  4. python conf配置文件
  5. SQL横表与纵表互转
  6. 用命令实现Win7远程桌面关机和重启
  7. centos安装python gcc sqlite
  8. php get获取cookie值,golang web开发获取get、post、cookie参数
  9. apache 支持php urlmanager,Yii中urlManager的配置
  10. d - 数据结构实验之查找四:二分查找_【数据结构】资料