10.5 线程相关的存储
到目前为止,本章所有讨论都集中于多线程对公共资源的同步访问上。然而,关于线程还有另一个方面,那就是线程相关的资源的提供,或者,用众所周知的说法就是TSS(Thread-Specific Storage,线程相关的存储)[Schm1997]。
10.5.1 重入
在单线程的程序中,在函数内部使用局部静态对象是提高函数易用性的一种合理方式。C标准库中就有若干函数采用了这种技术,例如strtok(),它基于一组字符分隔符将一个字符串标记化(tokenize)。
- char *strtok(char *str, const char *delimiterSet);
该函数在内部维护一个静态变量,它维护当前标记化点,从而后续的对该函数的调用(将NULL传给str)将会返回前字符串的一系列的标记(tokens)。
遗憾的是,在多线程情况下,这种函数意味着一个经典的竞争条件。当某个线程正在处理的途中,另一个线程可能会开始一个新的标记化过程。
跟其他竞争条件不同,这种情况下你不能使用同步对象来将访问串行化。那只会导致一个线程在使用该函数时其他线程都无法对内部标记化结构进行修改,而一个线程破坏另一个线程的标记化结果的情况仍然存在。
这里我们需要的并非对"线程全局"变量的访问进行串行化,而是提供"线程局部"变量。这正是TSS(线程相关存储)的由来。