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#includepthread_key_t key;pthread_once_t once_key=PTHREAD_ONCE_INIT;#ifdef _REENTRANTvoid myDestructor(void*p){ free(p);}void myCreateKey(void){ //创立key pthread_key_create(&key,myDestructor);}#endifchar* 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;}