自己实现的getenv和getenv_r,验证线程是否可重入,即是否线程安全
来源:互联网 发布:淘宝网聚划算天天特价 编辑:程序博客网 时间:2024/06/04 19:54
UNIX高级环境编程中说到getenv函数是不可重入的,因为它用的是全局的静态存储区,由于对它进行了些操作(strcpy)而没有加锁,所以当多个线程访问的时候会出现错误.
书上给了程序,如何验证呢,是个问题.所以我们可以把环境变量中的值重定向到文本文件中 ,命令如下:
env >log
获得log如下:
然后就可以模拟验证了.
程序如下:
#include <stdio.h>#include<string.h>#include<stdlib.h>#include<malloc.h>#include<pthread.h>#include<errno.h>#define NUM_MAX_ENVIRONMENT 100#define MAX 256static char envbuf[MAX];char **environ;struct msg{ char name[20]; char *buf; int buflen;};pthread_mutex_t env_mutex;static pthread_once_t init_done = PTHREAD_ONCE_INIT;static void thread_init(void){ //thread attirbute pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&env_mutex, &attr); pthread_mutexattr_destroy(&attr);}void *myGetenv_r(void * msg){ struct msg *my_msg = (struct msg *) msg; int i, len, olen; pthread_once(&init_done, thread_init); len = strlen(my_msg->name); pthread_mutex_lock(&env_mutex); for( i = 0; environ[i] != NULL; i++) { if(strncmp(environ[i], my_msg->name, len) == 0) if(environ[i][len] == '=') { olen =strlen(&environ[i][len+1]); if(olen > my_msg->buflen) { pthread_mutex_unlock(&env_mutex); return (void *)ENOSPC; } strcpy(my_msg->buf, &environ[i][len+1]); pthread_mutex_unlock(&env_mutex); return (void *)my_msg; } } pthread_mutex_unlock(&env_mutex); return (void *)ENOENT;}void *myGetenv(void * name){ char *my_name; my_name = (char *)name; int len =strlen(my_name); int i; for(i = 0; environ[i] != NULL; i++) { if(strncmp(environ[i], my_name, len) == 0) { if(environ[i][len] == '=') { strcpy(envbuf, &environ[i][len+1]); return envbuf; } } } return NULL;}void createEnviron(){ environ =(char **) malloc(NUM_MAX_ENVIRONMENT * sizeof(char *)); int i; for(i = 0; i < NUM_MAX_ENVIRONMENT; i++) { environ[i] = (char *) malloc(256); } char line[MAX]; int count =0; FILE *fp = fopen("log", "r"); while( fgets(line, MAX, fp) != NULL) { strcpy(environ[count], line); count++; } environ[count] = '\0'; fclose(fp);}void freeEnviron(){ int i; for(i = 0; i < NUM_MAX_ENVIRONMENT; i++) { free(environ[i]); } free(environ);}void printEnviron(){ int i; for(i = 0 ;environ[i] != NULL; i++) printf("%s", environ[i]);}void checkResults(int err){ if(err != 0) { printf("create thread failed!\n"); }}int main(){ createEnviron(); char name1[] = "PATH"; char name2[] = "LC_PAPER"; char name3[] = "JRE_HOME"; // create thread pthread_t tid1, tid2, tid3; int err = pthread_create(&tid1, NULL, myGetenv, (void *)name1); checkResults(err); err = pthread_create(&tid2, NULL, myGetenv, (void *)name2); checkResults(err); err = pthread_create(&tid3, NULL, myGetenv, (void *)name3); checkResults(err); void* tret1; void* tret2; void* tret3; pthread_join(tid1, &tret1); pthread_join(tid2, &tret2); pthread_join(tid3, &tret3); // char *str1 = (char *)myGetenv("PATH"); printf("%s \n", (char *)tret1); printf("%s \n", (char *)tret2); printf("%s \n", (char *)tret3); struct msg message4; strcpy(message4.name, "PATH"); message4.buflen = MAX; message4.buf = (char *) malloc(message4.buflen); struct msg message5; strcpy(message5.name, "LC_PAPER"); message5.buflen = MAX; message5.buf = (char *) malloc(message5.buflen); struct msg message6; strcpy(message6.name, "JRE_HOME"); message6.buflen = MAX; message6.buf = (char *) malloc(message6.buflen); pthread_t tid4, tid5, tid6; err = pthread_create(&tid4, NULL, myGetenv_r, (void *)&message4); checkResults(err); err = pthread_create(&tid5, NULL, myGetenv_r, (void *)&message5); checkResults(err); err = pthread_create(&tid6, NULL, myGetenv_r, (void *)&message6); checkResults(err); void* tret4; void* tret5; void* tret6; pthread_join(tid4, &tret4); pthread_join(tid5, &tret5); pthread_join(tid6, &tret6); //char *str1 = (char *)myGetenv("PATH"); printf("%s \n", ((struct msg *)tret4)->buf); printf("%s \n", ((struct msg *)tret5)->buf); printf("%s \n", ((struct msg *)tret6)->buf); struct msg * m1 = (struct msg *) tret4; struct msg * m2 = (struct msg *) tret5; struct msg * m3 = (struct msg *) tret6; printf("%s \n", m1->buf); printf("%s \n", m2->buf); printf("%s \n", m3->buf); printf("%s \n", message4.buf); printf("%s \n", message5.buf); printf("%s \n", message6.buf); free(message4.buf); free(message5.buf); free(message6.buf); freeEnviron(); return 0;}
获得的结果如下:
前三个输出的结果一模一样,不是我们想要的结果.getenv_r采用了线程自己的存储区.所以没有出现问题.
你可能会说,为啥用互斥锁,而不用读写锁呢?因为多个线程访问是,对log中读取和strcpy的写.
但并发的增强可能并不会很大程度上改善程序性能.
1.环境列表不长.
2.对getenv的调用不频繁使用.
因此没有必要
0 0
- 自己实现的getenv和getenv_r,验证线程是否可重入,即是否线程安全
- Action是否线程安全?
- Action是否线程安全?
- Action是否线程安全?
- DataGramSocket是否线程安全
- new线程是否安全
- Servlet是否线程安全
- Servlet 是否线程安全
- Servlet 是否线程安全
- Servlet是否线程安全
- SpringMVC和Struts是否线程安全
- 关于ConcurrentLinkedQueue是否线程安全的疑问
- 检查线程是否安全的小工具
- Linux下的strerror是否线程安全?
- servlet是否是线程安全的
- Servlet是否是线程安全的
- Uboot 中*getenv 、getenv_r 和env_get_char函数
- new 操作是否线程安全?
- 关于 app store
- 大家好
- @property( , ) set parameters
- 深入理解ecshop2.7.3整合discuzX3.2(97%的完美方案)
- JSP自定义标签开发+TLD文件元素详解
- 自己实现的getenv和getenv_r,验证线程是否可重入,即是否线程安全
- android AsyncTask介绍
- 希尔排序
- win7x64+vs2008下,visual assist过期之后再安装破解版VA仍提示过期的解决方案
- Sublime Text 2/3如何支持中文GBK编码
- Windows 下 android 自动打包 volley项目
- java基础之通过反射获得和使用类的字段、方法、构造器,等
- 解决win8安装完oracle_client没有Enterprise Management Console的问题
- DRBD实现的Hadoop的热备