查看文章 |
线程安全--strtok VS strtok_r
2009-03-30 22:44
#include<string.h> char *strtok(char* restrict s1,const char* restrict s2); strtok将字符串分隔成标记。对strtok的第一次调用与后继的调用不同。第一次调用的时候,将要解析的字符串地址作为第一个参数s1,传递进去。在后继的解析同一个字符串的调用中,用NULL作为第一个参数。 对strtok的每个后继调用都返回下一个标记的起始,并在返回的标记末尾插入一个'\0'。当strtok函数到达s1的末尾时,就返回NULL。 strtok没有为标记分配新的空间,而是就地对s1进行了标记,理解这一点是很重要的。因此,如果需要在调用该函数后访问原来的s1,就必须传递字符串的一个拷贝。 这两个参数使用的限定符restrict要求:这个函数中s1引用的任何对象都不能被s2访问。也就是说,被解析的字符串的末端不能用来包含定界符。 但是,strtok不是一个线程安全的函数。因为根据其定义,它必须使用内部静态变量来记录字符串中下一个需要解析的标记的当前位置。但是,由于指示这个位置的变量只有一个,那么,在同一个程序中出现多个解析不同字符串的strtok调用时,各自的字符串的解析就会互相干扰。 下面这个程序是一个用来确定一个文本中的每行单词个数的平均次数的错误算法。wordaverage函数用来确定每一行,不幸的是,wordcount函数也使用了strtok,这一次是用它来解析本行中的字,这时,strtok保持的内部状态信息被改变了=,= #include<string.h> #define LINE_DELIMITERS "\n" #define WORD_DELIMITERS " " static int wordcount(char *s) { int coutn=1; if(strtok(s,WORD_DELIMITERS)==NULL) return 0; while(strtok(NULL,WORD_DELIMITERS)!=NULL) count++; return count; } double wordaverage(char *s) { int linecount=1; char* nextline; int words; nextline=strtok(s,LINE_DELIMITERS); if(nextline==NULL) return 0.0; words=wordcount(nextline); while((nextline=strtok(NULL,LINE_DELIMITERS))!=NULL){ words+=wordcount(nextline); linecount++; } return (double)words/linecount; } POSIX定义了一个线程安全的函数——strtok_r,以此来代替strtok。_r表示可以重入(reentrant)。 #include<string.h> char * strtok_r(char* restrict s,const char* restrict sep,char **restrict lasts); 这样,对上面程序稍作修正,就能正确运行了。 #include<string.h> #define LINE_DELIMITERS "\n" #define WORD_DELIMITERS " " static int wordcount(char *s) { int coutn=1; char *lasts; if(strtok_r(s,WORD_DELIMITERS,&lasts)==NULL) return 0; while(strtok_r(NULL,WORD_DELIMITERS,&lasts)!=NULL) count++; return count; } double wordaverage(char *s) { int linecount=1; char* nextline; int words; char* lasts; nextline=strtok_r(s,LINE_DELIMITERS,&lasts); if(nextline==NULL) return 0.0; words=wordcount(nextline); while((nextline=strtok_r(NULL,LINE_DELIMITERS,&lasts))!=NULL){ words+=wordcount(nextline); linecount++; } return (double)words/linecount; } 除了额外的参数lasts外,strtok_r函数与strtok的表现类似,lasts是用户提供的一个指针,指向strtok_r用来存放下一次解析的起始地址的那个单元。 |
最近读者:

