GCC原子shared_ptr实现 [英] GCC atomic shared_ptr implementation

查看:168
本文介绍了GCC原子shared_ptr实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据 https://gcc.gnu.org/bugzilla /show_bug.cgi?id=57250 ,GCC 4.9支持原子 shared_ptr 操作。



使用GCC 4.9.2,我可以编译使用原子 shared_ptr 的程序。 -mcx16 标志是必需的,因为x86_64上的GCC实现显然需要 cmpxchg16b ,这是合理的,因为我会假设对 shared_ptr 的原子操作需要同时自动更新指针本身和引用计数。



<但是,当我试图实际使用 原子 shared_ptr 库时,它的行为并不像我期望的那样。所以,要么我没有正确使用它,要么GCC的实现是有缺陷的。大多数时候,我会99%相信我只是做错了,但由于这是一个相对较新的功能,并且由于行为看起来很奇怪,所以我只有50%的人相信这是我的错case。

这是一个简单的程序,它创建一个原子 shared_ptr ,然后执行一系列并发读写on the shared_ptr:

  void test()
{
std :: atomic< std :: shared_ptr<< ; INT>> p(std :: shared_ptr< int>(new int(10)));

std :: cout<< 使用次数:<< p.load()。use_count()<<的std :: ENDL;
std :: cout<< p的初始值:<< *(p.load())<<的std :: ENDL;

std :: vector< std :: thread>线程;
const std :: size_t num_threads = 8;

for(std :: size_t i = 0; i!= num_threads; ++ i)
{
threads.emplace_back([& p,i](){

std :: shared_ptr< int> x = p.load();
while(!p.compare_exchange_weak(
x,
std :: shared_ptr< int> (new int(i + 5))
));
});


for(auto& t:threads)t.join();

std :: cout<< 使用次数:<< p.load()。use_count()<<的std :: ENDL;
std :: cout<< p的最终值:<< *(p.load())<<的std :: ENDL;
}

当我编译并运行时,输出为:

 〜$ g ++ test2.cpp -o test2 -std = c ++ 11 -lpthread -mcx16 
〜$ ./test2
使用次数:1
初始值p:0
使用次数:0
p的最终值:0

但是这个输出对我来说没有意义。首先,在将原子 shared_ptr 初始化为 10 值后,当我加载并读取初始值(之前任何线程都会产生),我得到一个 0 。其次,在所有线程加入之后,即使没有线程可能将其设置为 0 0 >。最奇怪的是,在线程加入之后,shared_ptr的 use_count() 0 !然而原子 shared_ptr 对象仍然在作用域中,因此使用计数应该是 1

我很确定这里的GCC实现有缺陷,但根据我上面发布的链接,GCC 4.9有一个完整的原子 shared_ptr 执行,以及...

 〜$ gcc --version 
〜$ gcc( Debian 4.9.2-10)4.9.2

所以......这里究竟发生了什么?我想要得到某种确认,要么GCC 4.9.2实现在这里是有缺陷的或不完整的,或者我完全错误/困惑如何使用atomic shared_ptr

解决方案

atomic shared_ptr operations std :: atomic_(store | load | exchange | compare_exchange_strong | compare_exchange_weak)(_ explicit)? shared_ptr 的函数模板,有记录的此处。 (有趣的事实:它的实现实际上使用了全局的16个互斥体数组)。



实例化 std :: atomic over std :: shared_ptr 导致未定义的行为,如 std :: atomic std :: experimental :: atomic_shared_ptr

p>

According to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57250, GCC 4.9 has support for atomic shared_ptr operations.

Using GCC 4.9.2, I'm able to compile a program that uses atomic shared_ptr. The -mcx16 flag is required, as the GCC implementation on x86_64 apparently requires cmpxchg16b, which makes sense as I would assume that an atomic operation on a shared_ptr would require atomically updating both the pointer itself and the reference count at the same time.

However, when I try to actually use the atomic shared_ptr library, it does not behave as I expect. So, either I am not using this properly, or the GCC implementation is defective. Most of the time I'd be 99% confident that I'm just doing it wrong, but since this is a relatively new feature and since the behavior seems so bizarre, I'm only about 50% confident that it's my fault in this case.

Here is a simple program that creates an atomic shared_ptr, then performs a series of concurrent reads and writes on the shared_ptr:

void test()
{
        std::atomic<std::shared_ptr<int>> p(std::shared_ptr<int>(new int(10)));

        std::cout << "Use count : " << p.load().use_count() << std::endl;
        std::cout << "Initial value of p : " << *(p.load()) << std::endl;

        std::vector<std::thread> threads;
        const std::size_t num_threads = 8;

        for (std::size_t i = 0; i != num_threads; ++i)
        {
                threads.emplace_back([&p, i](){

                        std::shared_ptr<int> x = p.load();
                        while (!p.compare_exchange_weak(
                                x,
                                std::shared_ptr<int>(new int(i + 5))
                        )) ;
                });
        }

        for (auto& t : threads) t.join();

        std::cout << "Use count : " << p.load().use_count() << std::endl;
        std::cout << "Final value of p : " << *(p.load()) << std::endl;
}

When I compile and run, the output is:

~$ g++ test2.cpp -o test2 -std=c++11 -lpthread -mcx16
~$ ./test2
Use count : 1
Initial value of p : 0
Use count : 0
Final value of p : 0

But this output makes no sense to me. Firstly, after initializing the atomic shared_ptr to a value of 10, when I load it and read the initial value (before any threads are spawned), I get a 0. Secondly, after all the threads join, the value is still 0, even though no thread could have possibly set it to 0. And most bizarrely, after the threads join, the use_count() of the shared_ptr is 0! Yet the atomic shared_ptr object is still in scope, and thus the use count should be 1.

I'm pretty sure the GCC implementation is flawed here, but according to the link I posted above, GCC 4.9 has a completed atomic shared_ptr implementation, and...

~$ gcc --version
~$ gcc (Debian 4.9.2-10) 4.9.2

So... what exactly is going on here? I'd like to get some kind of confirmation that either the GCC 4.9.2 implementation here is flawed or incomplete, or I'm just totally wrong/confused about how to use atomic shared_ptr.

解决方案

"atomic shared_ptr operations" refers to the free std::atomic_(store|load|exchange|compare_exchange_strong|compare_exchange_weak)(_explicit)? function templates for shared_ptr, documented here. GCC doesn't have them until 5. (Fun fact: its implementation actually uses a global array of 16 mutexes under the hood.)

Instantiating std::atomic over std::shared_ptr results in undefined behavior, as std::atomic requires a trivially copyable type.

The concurrency TS has std::experimental::atomic_shared_ptr.

这篇关于GCC原子shared_ptr实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆