多线程编程指南

线程安全

线程安全可以避免数据竞争。 不管数据值设置的正确与否,都会出现数据争用的情况,具体取决于多个线程访问和修改数据的顺序。

不需要共享时,请为每个线程提供一个专用的数据副本。如果共享非常重要,则提供显式同步,以确保程序以确定的方式操作。

当某个过程由多个线程同时执行时,如果该过程在逻辑上是正确的,则认为该过程是线程安全的。实际上,一般可分为以下几种安全性级别。

通过将过程包含在语句中来锁定和解除锁定互斥,可以使不安全过程变成线程安全过程,而且可以进行串行化。示例 6–1 说明了 fputs() 的三个简化实现,最初线程是不安全的。

下面是此例程的可串行化版本,它使用单一互斥来防止过程出现并发执行问题。实际上,单一互斥比通常需要的同步效果更强。当两个线程使用 fputs() 将输出发送到不同文件时,一个线程无需等待另一个线程。只有在共享输出文件时,线程才需要进行同步。

最新版本是 MT 安全的。此版本对每个文件都使用一个锁定,允许两个线程同时指向不同的文件。因此,只要例程是线程安全的,该例程就是 MT 安全的,而且例程的执行不会对性能造成负面影响。


示例 6–1 线程安全程度

/* not thread-safe */

fputs(const char *s, FILE *stream) {

    char *p;

    for (p=s; *p; p++)

        putc((int)*p, stream);

}



/* serializable */

fputs(const char *s, FILE *stream) {

    static mutex_t mut;

    char *p;

    mutex_lock(&m);

    for (p=s; *p; p++)

        putc((int)*p, stream);



    mutex_unlock(&m);

}



/* MT-Safe */

mutex_t m[NFILE];

fputs(const char *s, FILE *stream) {

    static mutex_t mut;

    char *p;

    mutex_lock(&m[fileno(stream)]);

    for (p=s; *p; p++)

        putc((int)*p, stream);

    mutex_unlock(&m[fileno(stream)]0;

}