【问题标题】:Why does Apple clang disallow C++11 thread_local when 'official' clang supports it为什么 Apple clang 在“官方”clang 支持 C++11 thread_local 时不允许它
【发布时间】:2015-03-21 14:24:17
【问题描述】:

下面是一个简单的程序,它在共享库中使用非 POD 类型的 C++11 thread_local 变量进行测试。

如果我使用自制clang,这可以正常工作:

> /usr/local/Cellar/llvm/3.5.0_2/bin/clang --version                                          
clang version 3.5.0 (tags/RELEASE_350/final)
Target: x86_64-apple-darwin14.0.0
Thread model: posix

> cmake .. -G Ninja -DCMAKE_C_COMPILER=/usr/local/Cellar/llvm/3.5.0_2/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/Cellar/llvm/3.5.0_2/bin/clang++
-- The C compiler identification is Clang 3.5.0
-- The CXX compiler identification is Clang 3.5.0
-- Check for working C compiler using: Ninja
-- Check for working C compiler using: Ninja -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler using: Ninja
-- Check for working CXX compiler using: Ninja -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
> ninja all
...                                                                                      

>  ./main                                                                                       
XXX LifeCycle::LifeCycle 0x7fedc0c04b90
X before: -17
XXX LifeCycle::LifeCycle 0x7fedc0c04c10
X before in thread: -17
X after in thread: 2
XXX LifeCycle::~LifeCycle 0x7fedc0c04c10
X after: 1
XXX LifeCycle::~LifeCycle 0x7fedc0c04b90

但是,如果我尝试使用 Apple Clang,我会收到一条错误消息,指出它不受支持:

> /usr/bin/clang --version
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix
> cmake .. -G Ninja -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++
-- The C compiler identification is AppleClang 6.0.0.6000056
-- The CXX compiler identification is AppleClang 6.0.0.6000056
-- Check for working C compiler using: Ninja
-- Check for working C compiler using: Ninja -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler using: Ninja
-- Check for working CXX compiler using: Ninja -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to:

> ninja all
[1/4] Building CXX object CMakeFiles/lib.dir/lib.cpp.o
FAILED: /usr/bin/clang++   -Dlib_EXPORTS -Wall -std=c++11 -mmacosx-version-min=10.7 -stdlib=libc++ -fPIC -MMD -MT CMakeFiles/lib.dir/lib.cpp.o -MF CMakeFiles/lib.dir/lib.cpp.o.d -o CMakeFiles/lib.dir/lib.cpp.o -c ../lib.cpp
../lib.cpp:23:5: error: thread-local storage is unsupported for the current target
    thread_local LifeCycle lc;
    ^
1 error generated.
ninja: build stopped: subcommand failed.

任何人都可以提供任何见解,为什么 Apple 的 clang 变体怯懦地拒绝尊重 thread_local,尽管底层编译器支持它,并且生成的代码似乎可以工作?

lib.h:

#pragma once

int doit(int) __attribute__((__visibility__("default")));

lib.cpp:

#include "lib.h"

#include <thread>
#include <cstdlib>
#include <cstdio>

namespace {

    class LifeCycle {
    public:
        LifeCycle()
            : x(-17) {
            printf("XXX LifeCycle::LifeCycle %p\n", this);
        }

        ~LifeCycle() {
            printf("XXX LifeCycle::~LifeCycle %p\n", this);
        }

        int x;
    };

    thread_local LifeCycle lc;
} // namespace

int doit(int arg) {
    printf("X before: %d\n", lc.x);
    lc.x = arg;
    std::thread xwriter([arg]() {
            if (lc.x == arg)
                abort();
            printf("X before in thread: %d\n", lc.x);
            lc.x = arg + 1;
            printf("X after in thread: %d\n", lc.x);
        });
    xwriter.join();
    printf("X after: %d\n", lc.x);
    return (lc.x == arg ? EXIT_SUCCESS : EXIT_FAILURE);
}

main.cpp:

#include "lib.h"

int main(int argc, char* argv[]) {
    return doit(argc);
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.1)

set(CMAKE_CXX_FLAGS "-Wall -std=c++11 -mmacosx-version-min=10.7 -stdlib=libc++")

add_library(lib SHARED lib.cpp)
add_executable(main main.cpp)
target_link_libraries(main lib)

【问题讨论】:

  • @BrettHale Apple 在 XCode 6 中的官方 clang 版本基于 clang-3.5,clang-3.5 在 Darwin 上支持 thread_local。我相信在 clang-3.5 之前的版本中也是如此。
  • 可能是一个错误:stackoverflow.com/a/23850891/1392778

标签: xcode c++11 clang


【解决方案1】:

Xcode 8 及更高版本附带的 clang 编译器支持 C++11 thread_local 关键字。如the WWDC 2016 video "What's New in LLVM" 中所述,此功能已添加到 Xcode 8 beta 中,从the 5:50 mark 开始。 (external transcript)

问题中列出的示例程序在 OS X 10.11.6 下使用 Xcode 8 GM 编译和运行,并产生预期的输出。随后在 macOS 10.13.4 下使用 Xcode 9.3 和在 macOS 10.14.4 下使用 Xcode 10.2.1 进行了重新测试,并继续按预期运行。

关于iOS,我通过实验发现thread_local 支持iOS 9 及更高版本,但不支持iOS 8.4 或更早版本。


对于 Xcode 7.x 及更早版本,以下是 2014 年 Apple 工程师在旧 Apple 开发者论坛(不再可访问)上的回答:

我们不支持开源的 thread_local 实现 Clang 因为我们相信我们可以提供更高的性能 使用动态中的各种功能为我们的平台实现 链接器。这样的实现将与 ABI 不兼容 在开源 Clang 中实现,所以我们不支持 thread_local 直到我们得到一个我们可以接受的实现 可预见的未来。

随后的一篇文章证实 Xcode 6.3 仍然不支持 thread_local。

【讨论】:

  • 他们不想破坏 ABI 兼容性特定功能所以他们根本不提供该功能?那是精神上的。
  • 这真的很不幸。这意味着您仍然不能在可移植 C++11 中使用 thread_local,即使现在 VC14 支持它。如果有苹果的工程师读到这篇文章,我真的希望你能尽快修复它。
  • osx 提供的 clang 截至 2016 年 5 月 10 日仍然不支持 thread_local :( 我没有看到支持此功能的计划或计划,这很糟糕,因为 thread_local 会帮助解决对我来说是一个性能问题。
  • Apple 最终实现thread_local 的方式证明了为什么上面所有的批评都是错误的。他们一直等到他们有一个好的实现,他们可以保证永远稳定。这种理念正是 libSystem(Apple 的“CRT”)从未破坏二进制兼容性的原因,而 Microsoft 必须在每次编译器更改时发布新的 msvcrXYZ.dll/vcruntimeXYZ.dll。
  • 我正在确认 @rsfinn 2016 年 6 月 29 日的说明。Xcode 8 确实确实支持 thread_local,于 2016 年 9 月 20 日测试。我对 @alexchandel 的含义很感兴趣他们实施它的方式,但我的盘子里有太多东西无法充分研究它。
【解决方案2】:

根据http://clang.llvm.org/cxx_status.html:

thread_local 支持目前需要来自的 C++ 运行时库 g++-4.8 或更高版本

我相信自制版本的 clang 使用不同的 C++ 运行时。

【讨论】:

  • XCode 和 Homebrew clang 都能够使用 libstdc++ 和 libc++。由于 OS X 仅提供 GCC 4.1 老式 libstdc++,因此它不适用于 C++11。所以,我肯定在使用 libc++。尽管如此,它并没有回答为什么带有 libc++ 的自制程序可以使用 thread_local,但带有 libc++ 的 XCode 程序不能。
  • 这可能最好作为评论而不是答案发布。我想@HowardHinnant 知道真正的原因。
  • “格伦多尔:我可以召唤来自深渊的灵魂。急躁:为什么,我也可以,或者任何人都可以;但是当你召唤他们时,他们会来吗?”
【解决方案3】:

似乎在 macOS 上使用 __thread 代替了。

【讨论】:

    猜你喜欢
    • 2011-12-20
    • 1970-01-01
    • 2012-11-01
    • 2016-07-12
    • 2015-03-01
    • 2012-05-23
    • 2023-03-08
    • 2012-09-21
    • 1970-01-01
    相关资源
    最近更新 更多