我读了很多关于 strtok(char* s1, char* s2) 及其实现的内容。但是,我仍然不明白是什么使它成为在多线程程序中使用的危险函数。有人可以给我一个多线程程序的例子并解释那里的问题吗?请注意,我正在寻找一个可以向我展示问题所在的示例。
ps:strtok(char* s1, char* s2) 是C 标准库的一部分。
在第一次调用 strtok 时,您提供字符串和分隔符。在后续调用中,第一个参数为 NULL,您只需提供分隔符。strtok 会记住您传入的字符串。
在多线程环境中,这是危险的,因为许多线程可能使用不同的字符串调用 strtok。它只会记住最后一个并返回错误的结果。
这是一个具体的例子:
首先假设您的程序是多线程的,并且在一个执行线程中运行以下代码:
char str1[] = "split.me.up";
// call this line A
char *word1 = strtok(str1, "."); // returns "split", sets str1[5] = '\0'
// ...
// call this line B
char *word2 = strtok(NULL, "."); // we hope to get back "me"
Run Code Online (Sandbox Code Playgroud)
在另一个线程中,运行以下代码:
char str2[] = "multi;token;string";
// call this line C
char *token1 = strtok(str2, ";"); // returns "multi", sets str2[5] = '\0'
// ...
// call this line D
char *token2 = strtok(NULL, ";"); // we hope to get back "token"
Run Code Online (Sandbox Code Playgroud)
关键是,我们真的不知道word2and中会包含什么token2:
如果命令按照(A)、(B)、(C)、(D)的顺序运行,那么我们就会得到我们想要的结果。
.但是,如果命令按 (A)、(C)、(B)、(D) 的顺序运行,则命令 (B) 将在"token;string"!中搜索分隔符。这是因为NULL命令 (B) 的第一个参数告诉我们strtok继续在NULL传递的最后一个非搜索字符串中搜索,并且因为命令 (C) 已经运行,strtok因此将使用str2。
然后命令(B)将返回token;string,同时将搜索的新起始字符设置为NUL末尾的终止符str2。然后命令 (D) 会认为它正在搜索一个空字符串,因为它将在str2的NUL终止符处开始搜索,因此也会返回NULL。
即使您将命令 (A) 和 (B) 紧邻放置,并且命令 (C) 和 (D) 紧邻放置,也不能保证 (B) 会在 (A) 之后立即执行(C) 或 (D) 等
如果您创建某种互斥锁或备用防护来保护函数的使用strtok,并且仅从strtok已获得所述互斥锁的线程调用,则strtok可以安全使用。strtok_r然而,正如其他人所说,最好只使用线程安全。
编辑:还有一个问题,没有其他人提到过,即strtok修改并可能使用全局(或静态,等等)变量,并且以一种可能不是线程安全的方式执行此操作,所以即使您不这样做依赖于重复调用来strtok从同一字符串获取连续的“令牌”,在没有防护等的多线程环境中使用它可能不安全。
| 归档时间: |
|
| 查看次数: |
3078 次 |
| 最近记录: |