Chinaunix

标题: 跪求多线程安全的智能指针实现~ [打印本页]

作者: eagle518    时间: 2014-07-13 20:43
标题: 跪求多线程安全的智能指针实现~
本帖最后由 eagle518 于 2014-07-14 09:48 编辑

已知boost::shared_ptr如下验证多线程安全失败:

boost::shared_ptr<EString> g_shared_ptr(new EString("111"));

static void test_shared_ptr() {
        {
        boost::shared_ptr<EString> sx(new EString("x"));
        boost::shared_ptr<EString> sy(new EString("y"));
        sx = sy;
        LOG("x=%s, y=%s", sx->c_str(), sy->c_str());
        boost::shared_ptr<EString> sn;
//        sx = null;
        }

        class spReader : public EThread {
        public:
                virtual void run() {
               while (true) {
                       boost::shared_ptr<EString> local(g_shared_ptr);
                   LOG("s=%s", local->c_str());
               }
            }
        };

        class spWriter : public EThread {
        public:
                virtual void run() {
                        while (true) {
                                boost::shared_ptr<EString> newPtr(new EString("xxx"));
                                g_shared_ptr = newPtr;
               }
            }
        };

        EArray<EThread*> arr;
        int i;
        for (i = 0; i < 2; i++) {
                spReader* sThread1 = new spReader();
                sThread1->start();
                arr.add(sThread1);
        }

        for (i = 0; i < 3; i++) {
                spWriter* sThread2 = new spWriter();
                sThread2->start();
                arr.add(sThread2);
        }

        for (i = 0; i < arr.length(); i++) {
                arr.getAt(i)->join(NULL);
        }
}


请问有谁知道哪个开源智能指针实现是完全多线程安全的?
知道的请告知,不甚感激!

补充:lock-free实现更佳。


作者: webdna    时间: 2014-07-13 21:56
帮顶
作者: hellioncu    时间: 2014-07-14 08:34
本帖最后由 hellioncu 于 2014-07-14 08:35 编辑

这种情况下,我宁可不用智能指针
作者: eagle518    时间: 2014-07-14 09:48
why? 回复 3# hellioncu


   
作者: hellioncu    时间: 2014-07-14 09:54
eagle518 发表于 2014-07-14 09:48
why? 回复 3# hellioncu


根据业务逻辑,创建者和释放者应该能明确,在统一的地方自己手工释放看着也清楚
作者: eagle518    时间: 2014-07-14 10:05
可我现在的需求就是这样,我要实现仿JDK concurrent的类库,对象何时释放可以说是未知的。

回复 5# hellioncu


   
作者: shang2010    时间: 2014-07-14 10:22
java,好多人在用哈
作者: eagle518    时间: 2014-07-14 10:58
对,而且java api文档很好很全。
我现在要实现的就是把jdk c++话,已实现更好的性能,同时又易用易学。
回复 7# shang2010


   
作者: egmkang    时间: 2014-07-14 17:49
你需要去补充操作系统知识!!!
任何一个对象,在同一个时刻,最多只能允许一个线程去写. 这是最起码的常识.
而std::atomic<int>这种给你的错觉就是, 你可以开多个线程去同时写, 但是实际上从微观的角度讲, 多个CPU内核还是串行的执行写操作, 这是一个必然的.
如果你的对象非常复杂, 没法做到std::atomic<int>这种支持原子写操作, 那么你就需要用到锁, 不管是mutex还是spin lock,本质上都是锁.
作者: egmkang    时间: 2014-07-14 17:51
shared_ptr可以保证在多个线程间传递你的对象, 但是不能保证你自己那个对象的线程安全
shared_ptr的线程安全和你那个T类型的线程安全是两码事.
作者: eagle518    时间: 2014-07-14 20:32
回复 9# egmkang


不是无法实现多线程安全,参见:
http://stackoverflow.com/questio ... pointer-in-c-x86-64

当然,如果能lock-free实现更佳。
   
作者: windoze    时间: 2014-07-14 21:24
你这么用当然没法做到线程安全了,shared_ptr的线程安全保障等级“等同于内置类型”。
你仔细体会一下。
作者: eagle518    时间: 2014-07-14 23:29
回复 12# windoze


我的需求是实现java一样的对象引用,如果上述实现不合理,还望不吝赐教。


作者: windoze    时间: 2014-07-15 00:04
回复 13# eagle518

内置类型的线程安全基本上是这样的:
1、多个线程同时读取同一个对象是安全的
2、多个线程同时读取和写入同一个对象是不安全的
也就是说,下面的代码是安全的:

  1. int v=9527;
  2. // thread 1 entry
  3. void thread_func1() {
  4.     int sum=0
  5.     for(int i=0; i<100; i++) { sum+=v; }
  6. }
  7. // thread 2 entry
  8. void thread_func2() {
  9.     int sum=0
  10.     for(int i=0; i<100; i++) { sum+=v*2; }
  11. }
复制代码
下面的代码是不安全的

  1. int v=9527;
  2. // thread 1 entry
  3. void thread_func1() {
  4.     int sum=0
  5.     for(int i=0; i<100; i++) { v=i; }
  6. }
  7. // thread 2 entry
  8. void thread_func2() {
  9.     int sum=0
  10.     for(int i=0; i<100; i++) { sum+=v*2; }
  11. }
复制代码
另外,shared_ptr本身就是一个“对象”。

综上所述,你再仔细体会一下
作者: eagle518    时间: 2014-07-15 09:46
本帖最后由 eagle518 于 2014-07-15 09:47 编辑

回复 14# windoze


    内置类型线程安全我理解。

你能直接告诉我下面这段代码是否安全?若非安全,那问题会在哪里?

boost::shared_ptr<Object> ptr;
class Reader : public Thread {
    virtual void Run {
       for ( ; ; ) {
           boost::shared_ptr<Object> local(boost::atomic_load(&ptr));
           // do smth   
       }
    }   
};

class Writer : public Thread {
    virtual void Run {
       for ( ; ; ) {
           boost::shared_ptr<Object> newPtr(new Object);   
           boost::atomic_store(&ptr, newPtr);
       }
    }
};

int main() {
    Pool* pool = SystemThreadPool();
    pool->Run(new Reader());
    pool->Run(new Writer());
    for ( ; ; )
}


##实测运行我未发现上面的代码存在异常。

作者: windoze    时间: 2014-07-15 10:32
回复 15# eagle518

我不能直接告诉你代码是否安全,你要自己体会。
如果你真的知道内置类型的线程安全,share_ptr你也应该能体会出来。
作者: eagle518    时间: 2014-07-15 11:58
回复 16# windoze


我感觉你的理解还是框框在std::shared_prt或boost::shared_ptr的线程安全模型上,

我需要的是多线程读写安全的智能指针实现,加锁实现也可以,
而不是讨论std::shared_prt或boost::shared_ptr的线程安全仅是等同内置类型线程安全。
   
作者: windoze    时间: 2014-07-15 18:22
回复 17# eagle518

你看这里有两个“对象”,一个是smart pointer(std/boost::shared_ptr或者GC pointer或者别的什么东西),另一个是这个smart pointer指向的对象。
你有没有搞清楚你到底要哪个对象的“线程安全”呢?
作者: eagle518    时间: 2014-07-15 19:09
回复 18# windoze

显然,我要的是两者同时安全。
   
作者: windoze    时间: 2014-07-15 19:23
回复 19# eagle518

如果你真需要“两者同时安全”,那显然你需要给两个对象都加锁。

不过,你需要“两者同时安全”的原因是什么你搞清楚了吗?

作者: eagle518    时间: 2014-07-15 21:13
回复 20# windoze


    是的,需求很明确。
作者: windoze    时间: 2014-07-15 22:01
回复 21# eagle518

如果你需求很明确,那么解决方案也很明确——给smart pointer和它指向的对象各加一把锁。
作者: eagle518    时间: 2014-07-16 00:21
回复 22# windoze

晕,有没具体实现?
   
作者: windoze    时间: 2014-07-16 09:25
回复 23# eagle518

当然有拉,pthread_mutex_init/pthread_mutex_destroy/std::mutex/CreateEvent/CloseHandle,这不都是现成的?
作者: egmkang    时间: 2014-07-16 17:53
eagle518 发表于 2014-07-14 20:32
回复 9# egmkang


你还是没能理解我说的话,旁边也有一位朋友说的,你得用一把锁.
shared_ptr就是一张纸, 你可以把这个纸看成透明的
比如
shared_ptr<string> str;

string str;
在线程安全方面没有任何区别, 因为string并不支持并发写.
作者: windoze    时间: 2014-07-16 19:03
回复 25# egmkang

这个还是有点区别的,shared_ptr本身也不是线程安全的,你不能一边读一边写同一个shared_ptr对象。
作者: eagle518    时间: 2014-07-17 10:55
本帖最后由 eagle518 于 2014-07-17 10:56 编辑

回复 26# windoze
回复 25# egmkang


    我要的是具体实现,你们都理解错了。
    讲原理我也懂,而且我自己前面就已经实现了一个,但是用了spinlock,实测发现性能不高,
所以抛出这个问题寻找良好实现的线索。
作者: windoze    时间: 2014-07-17 17:43
回复 27# eagle518

你就直说要现成的不就结了?
作者: hello_wood    时间: 2014-07-17 17:53
有两种锁方案:shared_ptr类型共用一个锁,
或者每个被引用对象单独一个锁。
后者多了个锁对象管理。


要不就避免这种设计。
作者: eagle518    时间: 2014-07-17 19:51
回复 28# windoze


    可以这样说,但我更喜欢推荐开源实现,如果您熟悉的话。
作者: windoze    时间: 2014-07-17 21:51
回复 30# eagle518

木有+字数补丁




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2