【问题标题】:static const char [] in class thread safe?类线程中的静态 const char [] 安全吗?
【发布时间】:2013-03-15 15:05:52
【问题描述】:

static const 在类线程中是否安全?在下面的代码中,我有 trailingBytesForUTF8 这是一个 static const 字符数组。可能有许多线程拥有自己的CConvertUTF 类的对象实例。当多个线程同时访问同一个trailingBytesForUTF8 数组时,是否会出现任何可变状态问题,或者任何其他线程问题?另请注意,线程将永远共享CConvertUTF 类的相同对象实例。

// .h
class CConvertUTF final
{
    private:
        static const char trailingBytesForUTF8[256];
    public:
        bool IsLegalUTF8Sequence(const char *source, const char *sourceEnd);
        bool IsLegalUTF8(const char *source, int length);
};

// .cpp
const char CConvertUTF::trailingBytesForUTF8[256] = {
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
};

bool CConvertUTF::IsLegalUTF8Sequence(const char *source, const char *sourceEnd) {
    int length = trailingBytesForUTF8[*source]+1;
    if (source+length > sourceEnd) {
    return false;
    }
    return IsLegalUTF8(source, length);
}

bool CConvertUTF::IsLegalUTF8(const char *source, int length) {
    char a;
    const *char = source+length;
    switch (length) {
    default: return false;
    /* Everything else falls through when "true"... */
    case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
    case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
    case 2: if ((a = (*--srcptr)) > 0xBF) return false;

    switch (*source) {
        /* no fall-through in this inner switch */
        case 0xE0: if (a < 0xA0) return false; break;
        case 0xED: if (a > 0x9F) return false; break;
        case 0xF0: if (a < 0x90) return false; break;
        case 0xF4: if (a > 0x8F) return false; break;
        default:   if (a < 0x80) return false;
    }

    case 1: if (*source >= 0x80 && *source < 0xC2) return false;
    }
    if (*source > 0xF4) return false;
    return true;
}

【问题讨论】:

  • (嗯。鉴于const char test[] = { 0xA, 0xFF, 0xA }; IsLegalUTF8Sequence(test, test+3)true。)
  • @aschepler 感谢调试,代码是来自 Unicode Inc. 的旧开源代码,我刚刚添加了面向对象的编程风格。

标签: c++ multithreading static constants mutex


【解决方案1】:

只读 (const) 变量在销毁之前始终是线程安全的。由于静态对象仅在程序终止时被销毁,因此它们对程序的生命周期有益。

唯一的例外是具有mutable 成员的对象,但这不适用于char 数组。

【讨论】:

  • 提交者的示例(可能)是线程安全的,因为它将(可能)在创建任何新线程之前被初始化,但变量在没有互斥锁的情况下不是可靠的线程安全的,即使它们具有 const ,甚至是它们前面的静态常量,即使它们出现在全局空间中(因为您无法控制初始化顺序)。我认为这在 C++11 中已修复。
  • @Scott 我的回答基于一个假设,即这些变量将在任何备用线程可以启动之前被初始化。事后看来,另一个静态初始化可能会启动一个线程,或者静态变量可能处于块级别(函数内部)而不是类级别。对于静态 const POD 类型没有区别,因为初始化它们的通用方法是将它们的内容放入执行开始之前加载的代码空间。
  • 同意。我不知道标准是否保证这一点,但静态 POD 很可能在任何代码运行之前就存在。请注意,如果 pointer 本身不是 const(指向 const 数据但本身是非 const),则指针可能不会在 main() 之前初始化。我之所以提出这一切,是因为我们最近被一个带有惰性静态初始化(即 C::instance() { static C instance; return instance; })的单例类(使用了我的多个线程)所吸引,两个线程使用了单例“第一次”并同时运行构造函数——幸运的是,一个段错误帮助我们找到了错误。
【解决方案2】:

任何指定为static const 的数据都是全局的并且是只读的。

这意味着不受竞争条件的影响,因为没有人会修改数据。

要出现数据竞争条件,必须至少有写入操作

【讨论】:

  • 编译器可能会生成线程安全代码,只是在初始化任何其他对象之前“说”变量指向一个数据块,但由于不能保证初始化顺序,所以有一个多-即使使用“静态常量”数据也存在线程危险。我认为这在 C++11 中已修复。
猜你喜欢
  • 1970-01-01
  • 2012-09-22
  • 2015-03-24
  • 2010-11-08
  • 1970-01-01
  • 2020-08-01
  • 2019-05-21
  • 1970-01-01
相关资源
最近更新 更多