strtok函数和多线程

Naz*_*gol 1 c multithreading

我读了很多关于 strtok(c​​har* s1, char* s2) 及其实现的内容。但是,我仍然不明白是什么使它成为在多线程程序中使用的危险函数。有人可以给我一个多线程程序的例子并解释那里的问题吗?请注意,我正在寻找一个可以向我展示问题所在的示例。

ps:strtok(c​​har* s1, char* s2) 是C 标准库的一部分。

cup*_*cup 6

在第一次调用 strtok 时,您提供字符串和分隔符。在后续调用中,第一个参数为 NULL,您只需提供分隔符。strtok 会记住您传入的字符串。

在多线程环境中,这是危险的,因为许多线程可能使用不同的字符串调用 strtok。它只会记住最后一个并返回错误的结果。

  • 它不仅仅是多线程环境。strtok 在单线程环境中甚至很糟糕。如果高级函数使用 strtok 解析大对象(例如段落),然后调用使用 strtok 解析较小对象(例如句子)的较低级别函数,则较低级别的调用将干扰更高级别的调用。 (3认同)
  • '静态字符*lastToken = NULL; /* 不安全的共享状态!*/' 你还想要什么? (2认同)
  • @Nazgol:或者它们同时运行,导致各种破坏。 (2认同)

And*_*nko 6

这是一个具体的例子:

首先假设您的程序是多线程的,并且在一个执行线程中运行以下代码:

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) 会认为它正在搜索一个空字符串,因为它将在str2NUL终止符处开始搜索,因此也会返回NULL

即使您将命令 (A) 和 (B) 紧邻放置,并且命令 (C) 和 (D) 紧邻放置,也不能保证 (B) 会在 (A) 之后立即执行(C) 或 (D) 等

如果您创建某种互斥锁或备用防护来保护函数的使用strtok,并且仅从strtok已获得所述互斥锁的线程调用,则strtok可以安全使用。strtok_r然而,正如其他人所说,最好只使用线程安全。

编辑:还有一个问题,没有其他人提到过,即strtok修改并可能使用全局(或静态,等等)变量,并且以一种可能不是线程安全的方式执行此操作,所以即使您不这样做依赖于重复调用来strtok从同一字符串获取连续的“令牌”,在没有防护等的多线程环境中使用它可能不安全。