当一个库声称自己“不是线程安全的”(not thread-safe),意思是它在多线程环境下使用时,可能会出现数据竞争(data race)、未定义行为(undefined behavior)或不一致的结果。线程安全(thread-safety)是指一个库或数据结构在多个线程同时访问时,能够保证正确性和一致性,而无需用户额外添加同步机制(如锁)。
例如:
- C++ 的 std::cout(标准输出流)不是线程安全的。如果多个线程同时调用 std::cout << “Hello” << std::endl,输出可能会交错(如 HHelo),因为没有锁保护内部缓冲区。
线程安全意味着:
- 并发访问无冲突:多个线程可以同时调用库的函数或操作数据结构,且结果始终正确。
- 数据竞争:线程间不会意外覆盖彼此的数据。
- 原子性:操作要么全部完成,要么完全不执行,不会出现中间状态被其他线程看到
求解器 gurobi 与 cplex 都不是线程安全的,意味着不容易对他们使用并行计算(每个线程都要独立创建环境和模型)。
- 线程安全通常需要同步机制(如互斥锁
mutex、原子操作等),这些机制会增加性能开销。许多库为了追求最高性能,选择不内置线程安全支持,而是将同步责任交给用户。 - 我发现对于递归函数应用并行计算,相对于串行计算,没啥优势
非线程安全的常见表现:
- 数据竞争(Data Race):两个线程同时读写共享数据,没有同步机制,导致结果不可预测。
示例:std::vector 的 push_back 不是线程安全的,多个线程同时插入可能损坏内部数组。 - 非原子操作:一个操作需要多步完成,中间状态可能被其他线程干扰。
示例:C++ 的 std::string 修改(如 +=)不是原子的,多线程操作可能导致字符串损坏。 - 未定义行为:多线程访问非线程安全库可能触发 C++ 标准中的未定义行为(如崩溃、数据损坏)。
示例:C 的 errno 是全局变量,多线程使用可能导致错误码混淆。