SlideShare una empresa de Scribd logo
1 de 50
Descargar para leer sin conexión
Where destructors meet threads
Thread-safe object callbacks in C++


                 陈硕 Shuo Chen
              blog.csdn.net/Solstice
              giantchen@gmail.com
             blog.csdn.net/Solstice giantchen@gmail.com
                                                          2009-12   1
Intended audience
• C++ programmers aware of
  – tr1::shared_ptr, tr1::weak_ptr
  – tr1::function, tr1::bind
  – deadlocks and race conditions
  – Mutex and MutexLock




                blog.csdn.net/Solstice giantchen@gmail.com   2
当析构函数遇到多线程
                  C++ 中线程安全的对象回调

  这是陈硕在 2009 年上海 C++ 技术大会演讲的投影片,可自由用
于个人学习,其他使用需得到作者许可。

   编写线程安全的类不是难事,用同步原语保护内部状态即可。但是
对象的生与死不能由对象自身拥有的互斥器来保护。如何保证即将析构
对象 x 的时候,不会有另一个线程正在调用 x 的成员函数?或者说,如
何保证在执行 x 的成员函数期间,对象 x 不会在另一个线程被析构?如
何避免这种 race condition 是 C++ 多线程编程面临的基本问题,可以
借助 tr1 中的 shared_ptr 和 weak_ptr 完美解决。这也是实现线程安全
的 Observer 模式的必备技术。

    在此基础上,还将介绍一个线程安全的、contention-free 的
Signals/Slots 设计与实现,以及借助 shared_ptr 实现线程安全的
copy-on-write。   blog.csdn.net/Solstice giantchen@gmail.com
Agenda
• Part I                                                     45 min
  – Object lifetime management in multi-threads
• Mini QA                                                     5 min
• Part II                                                    30 min
  – Thread safe signals/slots
• QA                                                         10 min



                blog.csdn.net/Solstice giantchen@gmail.com            4
Object lifetime in multi-threads
• In C++, programmers manage lifetime of
  objects by themselves
• Things become much more complicated
  when multi-threading comes in to play
• When you are about to delete an object, how
  do you know that it is not being used in
  another thread?
• How can you tell if the object is still alive
  before you trying call its member function?
               blog.csdn.net/Solstice giantchen@gmail.com   5
Mutex and MutexLock
• Mutex wraps creation and destruction of
  – A CRITICAL_SECTION on Windows
  – A pthread_mutex_t on Linux
• MutexLock wraps acquiring and releasing
  – enter or leave critical section on Windows
  – lock or unlock pthreads mutex on Linux
• Both are not copy-constructible or assignable


                blog.csdn.net/Solstice giantchen@gmail.com   6
Thread safety
• A class is thread-safe
   – if it behaves correctly when accessed from
     multiple threads
   – regardless of the scheduling or interleaving of
     the execution of those threads by the OS
   – and with no additional synchronization or other
     coordination on the part of the calling code

Java Concurrency in Practice, by Brian Goetz et al.
                 blog.csdn.net/Solstice giantchen@gmail.com   7
A thread safe Counter class
• Write a thread safe class is not difficult
  – Protect internal state via synchronization
• How about its birth and death?
 class Counter : noncopyable         int64_t Counter::value() const
 {                                   {
  public:                              MutexLock lock(mutex_);
   Counter(): value_(0) {}             return value_;
   int64_t value() const;            }
   int64_t increase();               int64_t Counter::increase()
   int64_t decrease();               {
  private:                             MutexLock lock(mutex_);
   int64_t value_;                     int64_t ret = value_++;
   mutable Mutex mutex_;               return ret;
 }                                   }

                     blog.csdn.net/Solstice giantchen@gmail.com
                * In real world, atmoic operations are better for Counter.   8
Bear easily
 • Do not allow this pointer to escape during
   construction
    – Don't register to any callback in ctor (*)
    – Even at last line of ctor is also bad
    // Don't do this.             // Do this.
    class Foo : public Observer   class Foo : public Observer
    {                             { // ...
    public:                         void observe(Observable* s) {
      Foo(Observable* s) {            s->register(this);
        s->register(this); // X     }
      }                           };
      virtual void update();      Foo* pFoo = new Foo;
    };                            Observable* s = getIt();
                                  pFoo->observe(s);

(*) unless you know it will not call you back in any other thread
                     blog.csdn.net/Solstice giantchen@gmail.com 9
Die hard
• You can't tell if a object is alive by looking at
  the pointer or reference
  – if it's dead, an invalid object won't tell anything
  – set the pointer to NULL after delete? helpless
• There must be some alive object help us
  telling other object's state
• But, pointer and reference are not objects,
  they are primitive types

                 blog.csdn.net/Solstice giantchen@gmail.com   10
Mutex isn't the solution
• It only guarantees functions run sequentially
 Foo::~Foo()                         void Foo::update()
 {                                   {
   MutexLock lock(mutex_);             MutexLock lock(mutex_);
   // free internal state              // make use of internal state
 }                                   }
 // thread A                         // thread B
 delete x; x = NULL;                 if (x) x->update();


• What if x->~Foo() runs before x->update() ?
• There must be something outside the object
  to rescue.
   *Worse, mutex_ itself is a member of x, which has already been destroyed.
                       blog.csdn.net/Solstice giantchen@gmail.com         11
Mutex con't
• What's wrong of those function/operator ?
void swap(Counter& a, Counter& b) Counter& Counter::operator=(
{                                              const Counter& rhs)
  MutexLock aLock(a.mutex_);      {
  MutexLock bLock(b.mutex_);        if (this == &rhs)
  int64_t value = a.value_;           return;
  a.value_ = b.value_;
  b.value_ = value;                 MutexLock myLock(mutex_);
}                                   MutexLock itsLock(rhs.mutex_);
                                    value_ = rhs.value_;
// thread 1    // thread 2          return *this;
swap(a, b);    swap(b, a);        }




                     blog.csdn.net/Solstice giantchen@gmail.com   12
Member mutex
• Can help reading and writing of sibling members
• Can not help destructing
• Can not help reading then writing two objects,
  because of potential deadlocks
  – assignment operator
  – swap




                 blog.csdn.net/Solstice giantchen@gmail.com   13
How could this happen?
• Association relation                         non-permanent
  – a member pointer/reference to an object whose
    lifetime is not controlled by me
  – any kind of object callback
• Observer pattern
  – when the observable notifies observers, how
    does it know the observer is still alive?
• Observer unregisters itself in dtor?
  – not working, race condition exists
                blog.csdn.net/Solstice giantchen@gmail.com     14
Race condition
• Observer got deleted in one thread
• Calling its update() in another thread
struct Observable                struct Observer
{                                {
  void register(Observer* x);      virtual void update() = 0;
  void unregister(Observer* x);    void observe(Observable* s) {
  void notifyObservers() {           s->register(this);
    for each Observer* x:            subject_ = s;
      x->update(); // (1)          }
  }                                virtual ~Observer() {
  // ...                             // (2)
}                                    subject_->unregister(this);
                                   }
reach (2), switch to (1)           Observable* subject_;
Worse: Observer is a base class. };
                    blog.csdn.net/Solstice giantchen@gmail.com   15
Heuristics
• Raw pointers are bad, esp. when visible in
  other threads.
• Observable should store some thing other
  than raw Observer* pointer to tell if the
  observer still lives.
• So does Observer
• A smart pointer could do this
  – Not that simple, trick things happens
  – No worry, we will study them carefully
               blog.csdn.net/Solstice giantchen@gmail.com   16
The problem
• two raw pointers                     • object is deleted via p1
  (possible in threads)                • although p1 is set to 0
• to the same objects on               • p2 is a dangling pointer
  heap




                blog.csdn.net/Solstice giantchen@gmail.com
A "solution"
• two pointers                    •   delete the object by p1
• to a proxy on heap              •   set proxy to 0
• the proxy points to the         •   now p2 knows it's gone
  object                          •   when to delete proxy?




 Type* volatile proxy;         // to safely delete and set proxy to 0
                               Type* tmp = proxy;
                               proxy = NULL;
                               memory_barrier(); // flush the CPU cache
                               delete tmp;
                    blog.csdn.net/Solstice giantchen@gmail.com
A better solutoin
• sp1, sp2 are objects,
  not raw pointers
• proxy lives on heap,
  with a count member
• count=2 initially
• count=1 when sp1 dies
• count=0 when sp2 dies
  as well
• it is time to delete the
  object and the proxy
• reference counting, huh?
                blog.csdn.net/Solstice giantchen@gmail.com
Universal solution
• Another layer of indirection
• Calling through a proxy object, which
  always exists
  – either a value stored locally, or a global facade
• Handle/Body Idiom once more
• Wait! the standard library has exact what
  we need


                 blog.csdn.net/Solstice giantchen@gmail.com   20
shared_ptr/weak_ptr basics
• shared_ptr<T> is a reference counting smart
  pointer, available in boost and tr1
• It destroy the underlying object when the
  count goes down to zero
• weak_ptr is a rcsp without increasing the
  reference count, it can be promoted to a
  shared_ptr
• No explicit delete any more

              blog.csdn.net/Solstice giantchen@gmail.com   21
shared_ptr/weak_ptr con't
• shared_ptr controls the lifetime
  – The object is guaranteed to be deleted when the
    last shared_ptr pointing to it is destroyed or reset
• weak_ptr doesn't control
  – but it know whether the object is dead ♥
• Counting is atomic, thread safe and lock-free
  – _Interlocked(In|De)crement on Windows
  – "lock xadd" instruction on Linux/x86

• Use them as values
  – can be stored in std containers
                 blog.csdn.net/Solstice giantchen@gmail.com   22
Common pointer pitfalls
• Buffer overrun
  – vector or other standard containers
• Dangling pointer
  – shared_ptr/weak_ptr
• Double delete
  – scoped_ptr
• Memory leak
  – scoped_ptr
• Unpaired new[]/delete
  – vector, shared_array, scoped_array
                 blog.csdn.net/Solstice giantchen@gmail.com   23
Apply to observer
• Stores weak_ptr to Observer
  struct Observable { // not thread safe!
    void register(weak_ptr<Observer> x);
    void unregister(weak_ptr<Observer> x);
    void notifyObservers() {
      Iterator it = observers_.begin();
      while (it != observers_.end()) {
        shared_ptr<Observer> obj(it->lock());
        if (obj) {
          obj->update(); ++it;
        } else {
          it = observers_.erase(it);
        }
      }
    }
    vector<weak_ptr<Observer> > observers_;
  };
                   blog.csdn.net/Solstice giantchen@gmail.com   24
Outstanding issues
• Not flexible, should allow non-shared_ptr obj
• In dtor of Observer, it unregister itself from
  the Observable
  – What if Observable object goes out of scope?
• To make Observable thread safe, mutex is
  used in (un)register and notifyObservers
  – Will register/unregister be blocked for
    indeterminate period by notifyObservers?
• We will address them in Part II
                blog.csdn.net/Solstice giantchen@gmail.com   25
Pitfalls of shared_ptr
• Do not extend lifetime inadvertently
  – Why not store shared_ptr in Observable?
• Thread safety
  – same as built-ins, string and containers
• Used as function parameter
  – pass by const reference is Ok and efficient
    void doit(const shared_ptr<Foo>& pFoo)

  – as long as most outer caller holds an instance

                   blog.csdn.net/Solstice giantchen@gmail.com   26
An object cache
• Create Foo object for a new key
• Return the same Foo object for the same key
• But Foo never gets a chance to be deleted
  – even no one else holds it, except the cache
  class FooCache : boost::noncopyable
  {
   public:
    shared_ptr<Foo> get(const string& key);
   private:
    map<string, shared_ptr<Foo> > data_;
    mutable Mutex mutex_;
  };

                   blog.csdn.net/Solstice giantchen@gmail.com   27
weak_ptr to rescue (?)
• Memory leak! data_ keeps growing
 class FooCache : boost::noncopyable
 {
  public:
   shared_ptr<Foo> get(const string& key) {
     shared_ptr<Foo> pFoo;
     MutexLock lock(mutex_);
     weak_ptr<Foo>& wkFoo = data_[key];
     pFoo = wkFoo.lock();
     if (!pFoo) { pFoo.reset(new Foo(key)); wkFoo = pFoo; }
     return pFoo;
   }
  private:
   map<string, weak_ptr<Foo> > data_;
   mutable Mutex mutex_;
 };
                  blog.csdn.net/Solstice giantchen@gmail.com   28
Custom deallocator
• d(p) will be called for delecting the object
      shared_ptr(Y* p, D d); void reset(Y* p, D d);
  class FooCache : boost::noncopyable
  {
    // in get(), change pFoo.reset(new Foo(key)); to
    // pFoo.reset(new Foo(key),
    //            boost::bind(&FooCache::deleteFoo, this, _1));

   void deleteFoo(Foo* object) {
     if(object) {
       MutexLock lock(mutex_);
       data_.erase(object->key());
     }
     delete object; // sorry, I lied
   }
   // assuming FooCache lives longer than all Foo's ...
                   blog.csdn.net/Solstice giantchen@gmail.com   29
Is shared_ptr 100% thread safe?
• Not possible, it has two pointer members
  – A shared_ptr instance can be "read" (accessed
    using only const operations) simultaneously by
    multiple threads
  – Different shared_ptr instances can be "written to"
    (accessed using mutable operations such as
    operator= or reset) simultaneously by multiple
    threads, dtor is considered a "write access"
     • even when these instances are copies, and share the
       same reference count underneath
  – If a shared_ptr is to be read and written from
    multiple threads, protect both with mutex
        * http://www.boost.org/doc/libs/1_41_0/libs/smart_ptr/shared_ptr.htm
                    blog.csdn.net/Solstice giantchen@gmail.com           30
Safely read / write shared_ptr
shared_ptr<Foo> globalPtr;
Mutex mutex; // No need for ReaderWriterLock
void doit(const shared_ptr<Foo>& pFoo);


void read()                             void write()
{                                       {
  shared_ptr<Foo> ptr;                    shared_ptr<Foo> newptr(new Foo);
  {                                       {
    MutexLock lock(mutex);                  MutexLock lock(mutex);
    ptr = globalPtr;                        globalPtr = newptr;
  }                                       }

    // use ptr since here                   // use newptr since here
    doit(ptr);                              doit(newptr);
}                                       }

                      blog.csdn.net/Solstice giantchen@gmail.com        31
shared_ptr gotchas
• The destruction is captured at creation
   –   no virtual destructor is needed for T
   –   a shared_ptr<void> holds everything
   –   safely pass boundary of modules on Windows
   –   binary compatible even if object size changes
        • Given that all accessors must be out-lined
• Deletion happens in the same thread as the last
  shared_ptr goes out of scope, not necessary same
  thread of creation.
• An off-the-shelf RAII handle
   – be cautious of cycle referencing, lead to leaks
   – usually "A holds a shared_ptr to B, B holds a weak_ptr
     back to A, B is shared by As or A/C"
                       blog.csdn.net/Solstice giantchen@gmail.com   32
enable_shared_from_this
• Get a shared_ptr from this
• Only works if this object is held by shared_ptr
• Will not work in ctors
class FooCache : public boost::enable_shared_from_this<FooCache>,
                 boost::noncopyable
{ /* ... */ };

shared_ptr<FooCache> pCache(new FooCache);

shared_ptr<Foo> FooCache::get(const string& key) {
  // ...
  pFoo.reset(new Foo(key),
             boost::bind(&FooCache::deleteFoo,
                             shared_from_this(),
                             _1));
                     blog.csdn.net/Solstice giantchen@gmail.com
Alternatives
• A centralized object facade, all callbacks go
  through it.
  – calling two distinct objects from two threads
    shouldn't involve any lock. it's hard to
    implement within this model
• Roll your own proxy class
  – which simply does the same thing as shared_ptr



                blog.csdn.net/Solstice giantchen@gmail.com   34
Other languages?
• Java, C#
• Concurreny is hard without garbage
  collection
• GC languages will not face this problem,
  although they have their own.




               blog.csdn.net/Solstice giantchen@gmail.com   35
Take aways
• Manage lifecycle of objects with shared_ptr,
  especially in multi-thread programs.
• Otherwise you are reinventing wheel,
  similar but worse
• Use weak_ptr for notifications, caches, etc.
• Define your deallocator, for object pools



               blog.csdn.net/Solstice giantchen@gmail.com   36
Thread safe signals/slots

                  Part II




      blog.csdn.net/Solstice giantchen@gmail.com   37
What's wrong with Observer?
• Its Object-Oriented design
  – Observer is a base class
     • strong restriction/couple on type
  – To observe two events => multiple inheritance
     • call my create() when an order comes in
     • call my destroy() when the cafe closes
  – To observe same event twice => helper classes
     • call my start() member function 1 second later
     • call my stop() member function 10 seconds later

                 blog.csdn.net/Solstice giantchen@gmail.com   38
Signals/Slots
• A one-to-many callback, similar to Observer
  – a signal is an event
  – a slot is a callback executed when the signal is raised
  – one signal, many slots
• No restriction on types of slots
  – Any class can subscribe to any signal
• Can be done with standard libraries
  – Unlike QT, no preprocessing

                   blog.csdn.net/Solstice giantchen@gmail.com   39
A Timer, call me back later
class Timer // an easy way to do things later
{
 public:
  typedef boost::function<void ()> Callback;

  void runAfter(int time_in_ms, const Callback& cb);
  static Timer& instance();
  // ...
};

class Request
{
  void send() {
    Timer::instance().runAfter( // cancel me 10s later
        10*1000, boost::bind(&Request::cancel, this));
  }
  void cancel();
};
                 blog.csdn.net/Solstice giantchen@gmail.com   40
tr1::function and tr1::bind basics
• tr1::function is a genetic functor which
  references to any callable things.
• bind makes a function pointing to
  member functions of any class
  boost::function<void()> f;
  Foo* pFoo = new Foo;
  f = bind(&Foo::doit, pFoo);
  f(); // calls pFoo->doit()

  Bar bar; // possible bar is noncopyable
  f = bind(&Bar::dothat, boost::ref(bar));
  f(); // calls bar.dothat()


                   blog.csdn.net/Solstice giantchen@gmail.com   41
A new methodology of
         interface/library design
• function+bind = delegate in C#, Observer in Java
• Get rid of inheritance, base class, hierarchy
• Partial restriction on function signature, not on
  type or function name
• A replacement of Strategy/Command pattern
  – And many OO behavioural design patterns
• As fast as calling through member function
  pointer
                 blog.csdn.net/Solstice giantchen@gmail.com   42
A Thread class
class Thread : boost::noncopyable
{
 public:
  typedef boost::function<void()> Callback;
  Thread(Callback cb) : cb_(cb)
  { }
  void start() {
    /* some magic to call run() in new created thread */
  }
                    struct Foo
 private:
                    {
  void run() {
                      void run1();
    cb_();
                      void run2();
  }
                    };
  Callback cb_;
  // ...
                    Foo foo;
};
                    Thread thread1(boost::bind(&Foo::run1, &foo));
                    thread1.start();
                    Thread thread2(boost::bind(&Foo::run2, &foo));
                    thread2.start();
                    blog.csdn.net/Solstice giantchen@gmail.com   43
Caveats
• bind makes copy(-ies) of argument(s)
  – use boost::ref() when the object is noncopyable
  – shared_ptr tr1::function<void()> f;
                    shared_ptr<Foo> pFoo(new Foo);
                    f = bind(&Foo::doit, pFoo); // long life foo

• bind also takes parameter placeholders
  void Foo::xyz(int);
  function<void(int)> f = bind(&Foo::xyz, pFoo, _1);
  f(42); // pFoo->xyz(42);

  vector<Foo> foos;
  for_each(foos.begin(), foos.end(), bind(&Foo::xyz, _1, 42));
  // call Foo::xyz(42) on every objects in foos

                   blog.csdn.net/Solstice giantchen@gmail.com    44
Is Timer thread safe?
• No, same issue as Observer
• Unregisier in dtor does not work
• To make it safe, either
  – the timer guarantee the object not deleted
  – check its aliveness before calling cancel()




                blog.csdn.net/Solstice giantchen@gmail.com   45
Weak callback
class Request : public enable_shared_from_this<Request>
{
  static void timeoutCallback(boost::weak_ptr<Request> wkReq) {
    shared_ptr<Request> req(wkReq.lock());
    if (req) {
      req->cancel();
    }
  }

 void send() {
   Timer::instance().runAfter( // cancel me 10s later
       10*1000,
       boost::bind(&Request::timeoutCallback,
                   boost::weak_ptr<Request>(shared_from_this())));
 }

 // ...
                     blog.csdn.net/Solstice giantchen@gmail.com   46
Boost signals?
• Cons
  – Not thread safe
  – Not header only
  – auto unregister by inheriting trackable class
     • makes connecting multiple signals difficult
• Update 2010 Jan:
  – Boost.signals2 is thread safe and header only
  – The rest of slides can be ignored

                  blog.csdn.net/Solstice giantchen@gmail.com   47
Our Signal
• Synchronous, callback in the same thread
• Auto disconnecting at destructing Slot
  – No base class requirement
• Thread safe and race condition free
• Contention free
  – None of the methods will be blocked for
    uncertain time


               blog.csdn.net/Solstice giantchen@gmail.com   48
More take aways
• Replace class inheritance with
  boost::function and boost::bind, especially
  when design interfaces or libraries
• Copy-on-write for containers in signals, or
  data cache
• Use weak_ptr to break cycles



               blog.csdn.net/Solstice giantchen@gmail.com   49
Thanks!
         Q&A
blog.csdn.net/Solstice
giantchen@gmail.com



  blog.csdn.net/Solstice giantchen@gmail.com   50

Más contenido relacionado

La actualidad más candente

Jira Activity Timeline
Jira Activity TimelineJira Activity Timeline
Jira Activity TimelineOnlio
 
Micro-frontends with Angular 10 (Modern Web 2020)
Micro-frontends with Angular 10 (Modern Web 2020)Micro-frontends with Angular 10 (Modern Web 2020)
Micro-frontends with Angular 10 (Modern Web 2020)Will Huang
 
Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術Naoki Aoyama
 
채팅서버의 부하 분산 사례
채팅서버의 부하 분산 사례채팅서버의 부하 분산 사례
채팅서버의 부하 분산 사례John Kim
 
MySQLのソース・ターゲットエンドポイントとしての利用
MySQLのソース・ターゲットエンドポイントとしての利用MySQLのソース・ターゲットエンドポイントとしての利用
MySQLのソース・ターゲットエンドポイントとしての利用QlikPresalesJapan
 
TECHTALK 20210413 Qlik Sense の Analyzerで積極的なデータ活用!ログインからアラート設定まで
TECHTALK 20210413 Qlik Sense の Analyzerで積極的なデータ活用!ログインからアラート設定までTECHTALK 20210413 Qlik Sense の Analyzerで積極的なデータ活用!ログインからアラート設定まで
TECHTALK 20210413 Qlik Sense の Analyzerで積極的なデータ活用!ログインからアラート設定までQlikPresalesJapan
 
Spring超入門-Springと出会ってから1年半-
Spring超入門-Springと出会ってから1年半-Spring超入門-Springと出会ってから1年半-
Spring超入門-Springと出会ってから1年半-Ryosuke Uchitate
 
What is new in PostgreSQL 14?
What is new in PostgreSQL 14?What is new in PostgreSQL 14?
What is new in PostgreSQL 14?Mydbops
 
Qlik Tips 20230725 Section Access Update
Qlik Tips 20230725 Section Access UpdateQlik Tips 20230725 Section Access Update
Qlik Tips 20230725 Section Access UpdateQlikPresalesJapan
 
H3 2011 파이썬으로 클라우드 하고 싶어요_분산기술Lab_하용호
H3 2011 파이썬으로 클라우드 하고 싶어요_분산기술Lab_하용호H3 2011 파이썬으로 클라우드 하고 싶어요_분산기술Lab_하용호
H3 2011 파이썬으로 클라우드 하고 싶어요_분산기술Lab_하용호KTH, 케이티하이텔
 
어릴 적 할머니가 들려주신 옛 wsgi
어릴 적 할머니가 들려주신 옛 wsgi어릴 적 할머니가 들려주신 옛 wsgi
어릴 적 할머니가 들려주신 옛 wsgiHyun-Mook Choi
 
テスト自動化ツール[Selenium]を検討してみて
テスト自動化ツール[Selenium]を検討してみてテスト自動化ツール[Selenium]を検討してみて
テスト自動化ツール[Selenium]を検討してみて裕史 川松
 
[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정
[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정
[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정PgDay.Seoul
 
twMVC#44 讓我們用 k6 來進行壓測吧
twMVC#44 讓我們用 k6 來進行壓測吧twMVC#44 讓我們用 k6 來進行壓測吧
twMVC#44 讓我們用 k6 來進行壓測吧twMVC
 
映像コンテンツを自動生成するT2Vが広げる動画ビジネスの未来
映像コンテンツを自動生成するT2Vが広げる動画ビジネスの未来映像コンテンツを自動生成するT2Vが広げる動画ビジネスの未来
映像コンテンツを自動生成するT2Vが広げる動画ビジネスの未来Takesato Nigorikawa
 
Qlik Sense マッシュアップ開発 - SaaS版とWindows版でJWTによる認証
Qlik Sense マッシュアップ開発 - SaaS版とWindows版でJWTによる認証Qlik Sense マッシュアップ開発 - SaaS版とWindows版でJWTによる認証
Qlik Sense マッシュアップ開発 - SaaS版とWindows版でJWTによる認証QlikPresalesJapan
 
Qlik Sense パフォーマンスチートシート
Qlik Sense パフォーマンスチートシートQlik Sense パフォーマンスチートシート
Qlik Sense パフォーマンスチートシートQlikPresalesJapan
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modelingMario Fusco
 

La actualidad más candente (20)

Jira Activity Timeline
Jira Activity TimelineJira Activity Timeline
Jira Activity Timeline
 
Recursive Query Throwdown
Recursive Query ThrowdownRecursive Query Throwdown
Recursive Query Throwdown
 
Micro-frontends with Angular 10 (Modern Web 2020)
Micro-frontends with Angular 10 (Modern Web 2020)Micro-frontends with Angular 10 (Modern Web 2020)
Micro-frontends with Angular 10 (Modern Web 2020)
 
Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術
 
채팅서버의 부하 분산 사례
채팅서버의 부하 분산 사례채팅서버의 부하 분산 사례
채팅서버의 부하 분산 사례
 
MySQLのソース・ターゲットエンドポイントとしての利用
MySQLのソース・ターゲットエンドポイントとしての利用MySQLのソース・ターゲットエンドポイントとしての利用
MySQLのソース・ターゲットエンドポイントとしての利用
 
TECHTALK 20210413 Qlik Sense の Analyzerで積極的なデータ活用!ログインからアラート設定まで
TECHTALK 20210413 Qlik Sense の Analyzerで積極的なデータ活用!ログインからアラート設定までTECHTALK 20210413 Qlik Sense の Analyzerで積極的なデータ活用!ログインからアラート設定まで
TECHTALK 20210413 Qlik Sense の Analyzerで積極的なデータ活用!ログインからアラート設定まで
 
Spring超入門-Springと出会ってから1年半-
Spring超入門-Springと出会ってから1年半-Spring超入門-Springと出会ってから1年半-
Spring超入門-Springと出会ってから1年半-
 
What is new in PostgreSQL 14?
What is new in PostgreSQL 14?What is new in PostgreSQL 14?
What is new in PostgreSQL 14?
 
Qlik Tips 20230725 Section Access Update
Qlik Tips 20230725 Section Access UpdateQlik Tips 20230725 Section Access Update
Qlik Tips 20230725 Section Access Update
 
H3 2011 파이썬으로 클라우드 하고 싶어요_분산기술Lab_하용호
H3 2011 파이썬으로 클라우드 하고 싶어요_분산기술Lab_하용호H3 2011 파이썬으로 클라우드 하고 싶어요_분산기술Lab_하용호
H3 2011 파이썬으로 클라우드 하고 싶어요_분산기술Lab_하용호
 
어릴 적 할머니가 들려주신 옛 wsgi
어릴 적 할머니가 들려주신 옛 wsgi어릴 적 할머니가 들려주신 옛 wsgi
어릴 적 할머니가 들려주신 옛 wsgi
 
テスト自動化ツール[Selenium]を検討してみて
テスト自動化ツール[Selenium]を検討してみてテスト自動化ツール[Selenium]を検討してみて
テスト自動化ツール[Selenium]を検討してみて
 
[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정
[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정
[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정
 
twMVC#44 讓我們用 k6 來進行壓測吧
twMVC#44 讓我們用 k6 來進行壓測吧twMVC#44 讓我們用 k6 來進行壓測吧
twMVC#44 讓我們用 k6 來進行壓測吧
 
映像コンテンツを自動生成するT2Vが広げる動画ビジネスの未来
映像コンテンツを自動生成するT2Vが広げる動画ビジネスの未来映像コンテンツを自動生成するT2Vが広げる動画ビジネスの未来
映像コンテンツを自動生成するT2Vが広げる動画ビジネスの未来
 
Qlik Sense マッシュアップ開発 - SaaS版とWindows版でJWTによる認証
Qlik Sense マッシュアップ開発 - SaaS版とWindows版でJWTによる認証Qlik Sense マッシュアップ開発 - SaaS版とWindows版でJWTによる認証
Qlik Sense マッシュアップ開発 - SaaS版とWindows版でJWTによる認証
 
Qlik Sense パフォーマンスチートシート
Qlik Sense パフォーマンスチートシートQlik Sense パフォーマンスチートシート
Qlik Sense パフォーマンスチートシート
 
Ansible 101
Ansible 101Ansible 101
Ansible 101
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 

Destacado

Muduo network library
Muduo network libraryMuduo network library
Muduo network libraryShuo Chen
 
Essentials of Multithreaded System Programming in C++
Essentials of Multithreaded System Programming in C++Essentials of Multithreaded System Programming in C++
Essentials of Multithreaded System Programming in C++Shuo Chen
 
Efficient logging in multithreaded C++ server
Efficient logging in multithreaded C++ serverEfficient logging in multithreaded C++ server
Efficient logging in multithreaded C++ serverShuo Chen
 
Datetime - Julian Date
Datetime - Julian DateDatetime - Julian Date
Datetime - Julian DateShuo Chen
 
PThreads Vs Win32 Threads
PThreads  Vs  Win32 ThreadsPThreads  Vs  Win32 Threads
PThreads Vs Win32 ThreadsRobert Sayegh
 

Destacado (6)

Muduo network library
Muduo network libraryMuduo network library
Muduo network library
 
Essentials of Multithreaded System Programming in C++
Essentials of Multithreaded System Programming in C++Essentials of Multithreaded System Programming in C++
Essentials of Multithreaded System Programming in C++
 
Zurg part 1
Zurg part 1Zurg part 1
Zurg part 1
 
Efficient logging in multithreaded C++ server
Efficient logging in multithreaded C++ serverEfficient logging in multithreaded C++ server
Efficient logging in multithreaded C++ server
 
Datetime - Julian Date
Datetime - Julian DateDatetime - Julian Date
Datetime - Julian Date
 
PThreads Vs Win32 Threads
PThreads  Vs  Win32 ThreadsPThreads  Vs  Win32 Threads
PThreads Vs Win32 Threads
 

Similar a Where destructors meet threads: Thread-safe object callbacks in C

smart pointers are unique concept to avoid memory leakage
smart pointers are unique concept to avoid memory leakagesmart pointers are unique concept to avoid memory leakage
smart pointers are unique concept to avoid memory leakagedradeeljaved1
 
(3) cpp abstractions more_on_user_defined_types
(3) cpp abstractions more_on_user_defined_types(3) cpp abstractions more_on_user_defined_types
(3) cpp abstractions more_on_user_defined_typesNico Ludwig
 
Observer pattern with Stl, boost and qt
Observer pattern with Stl, boost and qtObserver pattern with Stl, boost and qt
Observer pattern with Stl, boost and qtDaniel Eriksson
 
Rainbow Over the Windows: More Colors Than You Could Expect
Rainbow Over the Windows: More Colors Than You Could ExpectRainbow Over the Windows: More Colors Than You Could Expect
Rainbow Over the Windows: More Colors Than You Could ExpectPeter Hlavaty
 
Rust "Hot or Not" at Sioux
Rust "Hot or Not" at SiouxRust "Hot or Not" at Sioux
Rust "Hot or Not" at Siouxnikomatsakis
 
Exploitation of counter overflows in the Linux kernel
Exploitation of counter overflows in the Linux kernelExploitation of counter overflows in the Linux kernel
Exploitation of counter overflows in the Linux kernelVitaly Nikolenko
 
Introduction to modern c++ principles(part 1)
Introduction to modern c++ principles(part 1)Introduction to modern c++ principles(part 1)
Introduction to modern c++ principles(part 1)Oky Firmansyah
 
[Ruxcon 2011] Post Memory Corruption Memory Analysis
[Ruxcon 2011] Post Memory Corruption Memory Analysis[Ruxcon 2011] Post Memory Corruption Memory Analysis
[Ruxcon 2011] Post Memory Corruption Memory AnalysisMoabi.com
 
Rust: Reach Further
Rust: Reach FurtherRust: Reach Further
Rust: Reach Furthernikomatsakis
 
Value Objects, Full Throttle (to be updated for spring TC39 meetings)
Value Objects, Full Throttle (to be updated for spring TC39 meetings)Value Objects, Full Throttle (to be updated for spring TC39 meetings)
Value Objects, Full Throttle (to be updated for spring TC39 meetings)Brendan Eich
 
A tour on Spur for non-VM experts
A tour on Spur for non-VM expertsA tour on Spur for non-VM experts
A tour on Spur for non-VM expertsESUG
 
[Kiwicon 2011] Post Memory Corruption Memory Analysis
[Kiwicon 2011] Post Memory Corruption Memory Analysis[Kiwicon 2011] Post Memory Corruption Memory Analysis
[Kiwicon 2011] Post Memory Corruption Memory AnalysisMoabi.com
 
Как мы охотимся на гонки (data races) или «найди багу до того, как она нашла ...
Как мы охотимся на гонки (data races) или «найди багу до того, как она нашла ...Как мы охотимся на гонки (data races) или «найди багу до того, как она нашла ...
Как мы охотимся на гонки (data races) или «найди багу до того, как она нашла ...yaevents
 
[HITB Malaysia 2011] Exploit Automation
[HITB Malaysia 2011] Exploit Automation[HITB Malaysia 2011] Exploit Automation
[HITB Malaysia 2011] Exploit AutomationMoabi.com
 
Tech Talks_04.07.15_Session 1_Jeni Markishka & Martin Hristov_Concurrent Prog...
Tech Talks_04.07.15_Session 1_Jeni Markishka & Martin Hristov_Concurrent Prog...Tech Talks_04.07.15_Session 1_Jeni Markishka & Martin Hristov_Concurrent Prog...
Tech Talks_04.07.15_Session 1_Jeni Markishka & Martin Hristov_Concurrent Prog...EPAM_Systems_Bulgaria
 
Concurrent programming without synchronization
Concurrent programming without synchronizationConcurrent programming without synchronization
Concurrent programming without synchronizationMartin Hristov
 
You didnt see it’s coming? "Dawn of hardened Windows Kernel"
You didnt see it’s coming? "Dawn of hardened Windows Kernel" You didnt see it’s coming? "Dawn of hardened Windows Kernel"
You didnt see it’s coming? "Dawn of hardened Windows Kernel" Peter Hlavaty
 

Similar a Where destructors meet threads: Thread-safe object callbacks in C (20)

Smart Pointers in C++
Smart Pointers in C++Smart Pointers in C++
Smart Pointers in C++
 
smart pointers are unique concept to avoid memory leakage
smart pointers are unique concept to avoid memory leakagesmart pointers are unique concept to avoid memory leakage
smart pointers are unique concept to avoid memory leakage
 
(3) cpp abstractions more_on_user_defined_types
(3) cpp abstractions more_on_user_defined_types(3) cpp abstractions more_on_user_defined_types
(3) cpp abstractions more_on_user_defined_types
 
Observer pattern with Stl, boost and qt
Observer pattern with Stl, boost and qtObserver pattern with Stl, boost and qt
Observer pattern with Stl, boost and qt
 
Rainbow Over the Windows: More Colors Than You Could Expect
Rainbow Over the Windows: More Colors Than You Could ExpectRainbow Over the Windows: More Colors Than You Could Expect
Rainbow Over the Windows: More Colors Than You Could Expect
 
Rust "Hot or Not" at Sioux
Rust "Hot or Not" at SiouxRust "Hot or Not" at Sioux
Rust "Hot or Not" at Sioux
 
Exploitation of counter overflows in the Linux kernel
Exploitation of counter overflows in the Linux kernelExploitation of counter overflows in the Linux kernel
Exploitation of counter overflows in the Linux kernel
 
Introduction to modern c++ principles(part 1)
Introduction to modern c++ principles(part 1)Introduction to modern c++ principles(part 1)
Introduction to modern c++ principles(part 1)
 
[Ruxcon 2011] Post Memory Corruption Memory Analysis
[Ruxcon 2011] Post Memory Corruption Memory Analysis[Ruxcon 2011] Post Memory Corruption Memory Analysis
[Ruxcon 2011] Post Memory Corruption Memory Analysis
 
Rust: Reach Further
Rust: Reach FurtherRust: Reach Further
Rust: Reach Further
 
Value Objects, Full Throttle (to be updated for spring TC39 meetings)
Value Objects, Full Throttle (to be updated for spring TC39 meetings)Value Objects, Full Throttle (to be updated for spring TC39 meetings)
Value Objects, Full Throttle (to be updated for spring TC39 meetings)
 
A tour on Spur for non-VM experts
A tour on Spur for non-VM expertsA tour on Spur for non-VM experts
A tour on Spur for non-VM experts
 
[Kiwicon 2011] Post Memory Corruption Memory Analysis
[Kiwicon 2011] Post Memory Corruption Memory Analysis[Kiwicon 2011] Post Memory Corruption Memory Analysis
[Kiwicon 2011] Post Memory Corruption Memory Analysis
 
Как мы охотимся на гонки (data races) или «найди багу до того, как она нашла ...
Как мы охотимся на гонки (data races) или «найди багу до того, как она нашла ...Как мы охотимся на гонки (data races) или «найди багу до того, как она нашла ...
Как мы охотимся на гонки (data races) или «найди багу до того, как она нашла ...
 
Lect04
Lect04Lect04
Lect04
 
[HITB Malaysia 2011] Exploit Automation
[HITB Malaysia 2011] Exploit Automation[HITB Malaysia 2011] Exploit Automation
[HITB Malaysia 2011] Exploit Automation
 
Tech Talks_04.07.15_Session 1_Jeni Markishka & Martin Hristov_Concurrent Prog...
Tech Talks_04.07.15_Session 1_Jeni Markishka & Martin Hristov_Concurrent Prog...Tech Talks_04.07.15_Session 1_Jeni Markishka & Martin Hristov_Concurrent Prog...
Tech Talks_04.07.15_Session 1_Jeni Markishka & Martin Hristov_Concurrent Prog...
 
Concurrent programming without synchronization
Concurrent programming without synchronizationConcurrent programming without synchronization
Concurrent programming without synchronization
 
One Careful Owner
One Careful OwnerOne Careful Owner
One Careful Owner
 
You didnt see it’s coming? "Dawn of hardened Windows Kernel"
You didnt see it’s coming? "Dawn of hardened Windows Kernel" You didnt see it’s coming? "Dawn of hardened Windows Kernel"
You didnt see it’s coming? "Dawn of hardened Windows Kernel"
 

Último

Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 

Último (20)

Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 

Where destructors meet threads: Thread-safe object callbacks in C

  • 1. Where destructors meet threads Thread-safe object callbacks in C++ 陈硕 Shuo Chen blog.csdn.net/Solstice giantchen@gmail.com blog.csdn.net/Solstice giantchen@gmail.com 2009-12 1
  • 2. Intended audience • C++ programmers aware of – tr1::shared_ptr, tr1::weak_ptr – tr1::function, tr1::bind – deadlocks and race conditions – Mutex and MutexLock blog.csdn.net/Solstice giantchen@gmail.com 2
  • 3. 当析构函数遇到多线程 C++ 中线程安全的对象回调 这是陈硕在 2009 年上海 C++ 技术大会演讲的投影片,可自由用 于个人学习,其他使用需得到作者许可。 编写线程安全的类不是难事,用同步原语保护内部状态即可。但是 对象的生与死不能由对象自身拥有的互斥器来保护。如何保证即将析构 对象 x 的时候,不会有另一个线程正在调用 x 的成员函数?或者说,如 何保证在执行 x 的成员函数期间,对象 x 不会在另一个线程被析构?如 何避免这种 race condition 是 C++ 多线程编程面临的基本问题,可以 借助 tr1 中的 shared_ptr 和 weak_ptr 完美解决。这也是实现线程安全 的 Observer 模式的必备技术。 在此基础上,还将介绍一个线程安全的、contention-free 的 Signals/Slots 设计与实现,以及借助 shared_ptr 实现线程安全的 copy-on-write。 blog.csdn.net/Solstice giantchen@gmail.com
  • 4. Agenda • Part I 45 min – Object lifetime management in multi-threads • Mini QA 5 min • Part II 30 min – Thread safe signals/slots • QA 10 min blog.csdn.net/Solstice giantchen@gmail.com 4
  • 5. Object lifetime in multi-threads • In C++, programmers manage lifetime of objects by themselves • Things become much more complicated when multi-threading comes in to play • When you are about to delete an object, how do you know that it is not being used in another thread? • How can you tell if the object is still alive before you trying call its member function? blog.csdn.net/Solstice giantchen@gmail.com 5
  • 6. Mutex and MutexLock • Mutex wraps creation and destruction of – A CRITICAL_SECTION on Windows – A pthread_mutex_t on Linux • MutexLock wraps acquiring and releasing – enter or leave critical section on Windows – lock or unlock pthreads mutex on Linux • Both are not copy-constructible or assignable blog.csdn.net/Solstice giantchen@gmail.com 6
  • 7. Thread safety • A class is thread-safe – if it behaves correctly when accessed from multiple threads – regardless of the scheduling or interleaving of the execution of those threads by the OS – and with no additional synchronization or other coordination on the part of the calling code Java Concurrency in Practice, by Brian Goetz et al. blog.csdn.net/Solstice giantchen@gmail.com 7
  • 8. A thread safe Counter class • Write a thread safe class is not difficult – Protect internal state via synchronization • How about its birth and death? class Counter : noncopyable int64_t Counter::value() const { { public: MutexLock lock(mutex_); Counter(): value_(0) {} return value_; int64_t value() const; } int64_t increase(); int64_t Counter::increase() int64_t decrease(); { private: MutexLock lock(mutex_); int64_t value_; int64_t ret = value_++; mutable Mutex mutex_; return ret; } } blog.csdn.net/Solstice giantchen@gmail.com * In real world, atmoic operations are better for Counter. 8
  • 9. Bear easily • Do not allow this pointer to escape during construction – Don't register to any callback in ctor (*) – Even at last line of ctor is also bad // Don't do this. // Do this. class Foo : public Observer class Foo : public Observer { { // ... public: void observe(Observable* s) { Foo(Observable* s) { s->register(this); s->register(this); // X } } }; virtual void update(); Foo* pFoo = new Foo; }; Observable* s = getIt(); pFoo->observe(s); (*) unless you know it will not call you back in any other thread blog.csdn.net/Solstice giantchen@gmail.com 9
  • 10. Die hard • You can't tell if a object is alive by looking at the pointer or reference – if it's dead, an invalid object won't tell anything – set the pointer to NULL after delete? helpless • There must be some alive object help us telling other object's state • But, pointer and reference are not objects, they are primitive types blog.csdn.net/Solstice giantchen@gmail.com 10
  • 11. Mutex isn't the solution • It only guarantees functions run sequentially Foo::~Foo() void Foo::update() { { MutexLock lock(mutex_); MutexLock lock(mutex_); // free internal state // make use of internal state } } // thread A // thread B delete x; x = NULL; if (x) x->update(); • What if x->~Foo() runs before x->update() ? • There must be something outside the object to rescue. *Worse, mutex_ itself is a member of x, which has already been destroyed. blog.csdn.net/Solstice giantchen@gmail.com 11
  • 12. Mutex con't • What's wrong of those function/operator ? void swap(Counter& a, Counter& b) Counter& Counter::operator=( { const Counter& rhs) MutexLock aLock(a.mutex_); { MutexLock bLock(b.mutex_); if (this == &rhs) int64_t value = a.value_; return; a.value_ = b.value_; b.value_ = value; MutexLock myLock(mutex_); } MutexLock itsLock(rhs.mutex_); value_ = rhs.value_; // thread 1 // thread 2 return *this; swap(a, b); swap(b, a); } blog.csdn.net/Solstice giantchen@gmail.com 12
  • 13. Member mutex • Can help reading and writing of sibling members • Can not help destructing • Can not help reading then writing two objects, because of potential deadlocks – assignment operator – swap blog.csdn.net/Solstice giantchen@gmail.com 13
  • 14. How could this happen? • Association relation non-permanent – a member pointer/reference to an object whose lifetime is not controlled by me – any kind of object callback • Observer pattern – when the observable notifies observers, how does it know the observer is still alive? • Observer unregisters itself in dtor? – not working, race condition exists blog.csdn.net/Solstice giantchen@gmail.com 14
  • 15. Race condition • Observer got deleted in one thread • Calling its update() in another thread struct Observable struct Observer { { void register(Observer* x); virtual void update() = 0; void unregister(Observer* x); void observe(Observable* s) { void notifyObservers() { s->register(this); for each Observer* x: subject_ = s; x->update(); // (1) } } virtual ~Observer() { // ... // (2) } subject_->unregister(this); } reach (2), switch to (1) Observable* subject_; Worse: Observer is a base class. }; blog.csdn.net/Solstice giantchen@gmail.com 15
  • 16. Heuristics • Raw pointers are bad, esp. when visible in other threads. • Observable should store some thing other than raw Observer* pointer to tell if the observer still lives. • So does Observer • A smart pointer could do this – Not that simple, trick things happens – No worry, we will study them carefully blog.csdn.net/Solstice giantchen@gmail.com 16
  • 17. The problem • two raw pointers • object is deleted via p1 (possible in threads) • although p1 is set to 0 • to the same objects on • p2 is a dangling pointer heap blog.csdn.net/Solstice giantchen@gmail.com
  • 18. A "solution" • two pointers • delete the object by p1 • to a proxy on heap • set proxy to 0 • the proxy points to the • now p2 knows it's gone object • when to delete proxy? Type* volatile proxy; // to safely delete and set proxy to 0 Type* tmp = proxy; proxy = NULL; memory_barrier(); // flush the CPU cache delete tmp; blog.csdn.net/Solstice giantchen@gmail.com
  • 19. A better solutoin • sp1, sp2 are objects, not raw pointers • proxy lives on heap, with a count member • count=2 initially • count=1 when sp1 dies • count=0 when sp2 dies as well • it is time to delete the object and the proxy • reference counting, huh? blog.csdn.net/Solstice giantchen@gmail.com
  • 20. Universal solution • Another layer of indirection • Calling through a proxy object, which always exists – either a value stored locally, or a global facade • Handle/Body Idiom once more • Wait! the standard library has exact what we need blog.csdn.net/Solstice giantchen@gmail.com 20
  • 21. shared_ptr/weak_ptr basics • shared_ptr<T> is a reference counting smart pointer, available in boost and tr1 • It destroy the underlying object when the count goes down to zero • weak_ptr is a rcsp without increasing the reference count, it can be promoted to a shared_ptr • No explicit delete any more blog.csdn.net/Solstice giantchen@gmail.com 21
  • 22. shared_ptr/weak_ptr con't • shared_ptr controls the lifetime – The object is guaranteed to be deleted when the last shared_ptr pointing to it is destroyed or reset • weak_ptr doesn't control – but it know whether the object is dead ♥ • Counting is atomic, thread safe and lock-free – _Interlocked(In|De)crement on Windows – "lock xadd" instruction on Linux/x86 • Use them as values – can be stored in std containers blog.csdn.net/Solstice giantchen@gmail.com 22
  • 23. Common pointer pitfalls • Buffer overrun – vector or other standard containers • Dangling pointer – shared_ptr/weak_ptr • Double delete – scoped_ptr • Memory leak – scoped_ptr • Unpaired new[]/delete – vector, shared_array, scoped_array blog.csdn.net/Solstice giantchen@gmail.com 23
  • 24. Apply to observer • Stores weak_ptr to Observer struct Observable { // not thread safe! void register(weak_ptr<Observer> x); void unregister(weak_ptr<Observer> x); void notifyObservers() { Iterator it = observers_.begin(); while (it != observers_.end()) { shared_ptr<Observer> obj(it->lock()); if (obj) { obj->update(); ++it; } else { it = observers_.erase(it); } } } vector<weak_ptr<Observer> > observers_; }; blog.csdn.net/Solstice giantchen@gmail.com 24
  • 25. Outstanding issues • Not flexible, should allow non-shared_ptr obj • In dtor of Observer, it unregister itself from the Observable – What if Observable object goes out of scope? • To make Observable thread safe, mutex is used in (un)register and notifyObservers – Will register/unregister be blocked for indeterminate period by notifyObservers? • We will address them in Part II blog.csdn.net/Solstice giantchen@gmail.com 25
  • 26. Pitfalls of shared_ptr • Do not extend lifetime inadvertently – Why not store shared_ptr in Observable? • Thread safety – same as built-ins, string and containers • Used as function parameter – pass by const reference is Ok and efficient void doit(const shared_ptr<Foo>& pFoo) – as long as most outer caller holds an instance blog.csdn.net/Solstice giantchen@gmail.com 26
  • 27. An object cache • Create Foo object for a new key • Return the same Foo object for the same key • But Foo never gets a chance to be deleted – even no one else holds it, except the cache class FooCache : boost::noncopyable { public: shared_ptr<Foo> get(const string& key); private: map<string, shared_ptr<Foo> > data_; mutable Mutex mutex_; }; blog.csdn.net/Solstice giantchen@gmail.com 27
  • 28. weak_ptr to rescue (?) • Memory leak! data_ keeps growing class FooCache : boost::noncopyable { public: shared_ptr<Foo> get(const string& key) { shared_ptr<Foo> pFoo; MutexLock lock(mutex_); weak_ptr<Foo>& wkFoo = data_[key]; pFoo = wkFoo.lock(); if (!pFoo) { pFoo.reset(new Foo(key)); wkFoo = pFoo; } return pFoo; } private: map<string, weak_ptr<Foo> > data_; mutable Mutex mutex_; }; blog.csdn.net/Solstice giantchen@gmail.com 28
  • 29. Custom deallocator • d(p) will be called for delecting the object shared_ptr(Y* p, D d); void reset(Y* p, D d); class FooCache : boost::noncopyable { // in get(), change pFoo.reset(new Foo(key)); to // pFoo.reset(new Foo(key), // boost::bind(&FooCache::deleteFoo, this, _1)); void deleteFoo(Foo* object) { if(object) { MutexLock lock(mutex_); data_.erase(object->key()); } delete object; // sorry, I lied } // assuming FooCache lives longer than all Foo's ... blog.csdn.net/Solstice giantchen@gmail.com 29
  • 30. Is shared_ptr 100% thread safe? • Not possible, it has two pointer members – A shared_ptr instance can be "read" (accessed using only const operations) simultaneously by multiple threads – Different shared_ptr instances can be "written to" (accessed using mutable operations such as operator= or reset) simultaneously by multiple threads, dtor is considered a "write access" • even when these instances are copies, and share the same reference count underneath – If a shared_ptr is to be read and written from multiple threads, protect both with mutex * http://www.boost.org/doc/libs/1_41_0/libs/smart_ptr/shared_ptr.htm blog.csdn.net/Solstice giantchen@gmail.com 30
  • 31. Safely read / write shared_ptr shared_ptr<Foo> globalPtr; Mutex mutex; // No need for ReaderWriterLock void doit(const shared_ptr<Foo>& pFoo); void read() void write() { { shared_ptr<Foo> ptr; shared_ptr<Foo> newptr(new Foo); { { MutexLock lock(mutex); MutexLock lock(mutex); ptr = globalPtr; globalPtr = newptr; } } // use ptr since here // use newptr since here doit(ptr); doit(newptr); } } blog.csdn.net/Solstice giantchen@gmail.com 31
  • 32. shared_ptr gotchas • The destruction is captured at creation – no virtual destructor is needed for T – a shared_ptr<void> holds everything – safely pass boundary of modules on Windows – binary compatible even if object size changes • Given that all accessors must be out-lined • Deletion happens in the same thread as the last shared_ptr goes out of scope, not necessary same thread of creation. • An off-the-shelf RAII handle – be cautious of cycle referencing, lead to leaks – usually "A holds a shared_ptr to B, B holds a weak_ptr back to A, B is shared by As or A/C" blog.csdn.net/Solstice giantchen@gmail.com 32
  • 33. enable_shared_from_this • Get a shared_ptr from this • Only works if this object is held by shared_ptr • Will not work in ctors class FooCache : public boost::enable_shared_from_this<FooCache>, boost::noncopyable { /* ... */ }; shared_ptr<FooCache> pCache(new FooCache); shared_ptr<Foo> FooCache::get(const string& key) { // ... pFoo.reset(new Foo(key), boost::bind(&FooCache::deleteFoo, shared_from_this(), _1)); blog.csdn.net/Solstice giantchen@gmail.com
  • 34. Alternatives • A centralized object facade, all callbacks go through it. – calling two distinct objects from two threads shouldn't involve any lock. it's hard to implement within this model • Roll your own proxy class – which simply does the same thing as shared_ptr blog.csdn.net/Solstice giantchen@gmail.com 34
  • 35. Other languages? • Java, C# • Concurreny is hard without garbage collection • GC languages will not face this problem, although they have their own. blog.csdn.net/Solstice giantchen@gmail.com 35
  • 36. Take aways • Manage lifecycle of objects with shared_ptr, especially in multi-thread programs. • Otherwise you are reinventing wheel, similar but worse • Use weak_ptr for notifications, caches, etc. • Define your deallocator, for object pools blog.csdn.net/Solstice giantchen@gmail.com 36
  • 37. Thread safe signals/slots Part II blog.csdn.net/Solstice giantchen@gmail.com 37
  • 38. What's wrong with Observer? • Its Object-Oriented design – Observer is a base class • strong restriction/couple on type – To observe two events => multiple inheritance • call my create() when an order comes in • call my destroy() when the cafe closes – To observe same event twice => helper classes • call my start() member function 1 second later • call my stop() member function 10 seconds later blog.csdn.net/Solstice giantchen@gmail.com 38
  • 39. Signals/Slots • A one-to-many callback, similar to Observer – a signal is an event – a slot is a callback executed when the signal is raised – one signal, many slots • No restriction on types of slots – Any class can subscribe to any signal • Can be done with standard libraries – Unlike QT, no preprocessing blog.csdn.net/Solstice giantchen@gmail.com 39
  • 40. A Timer, call me back later class Timer // an easy way to do things later { public: typedef boost::function<void ()> Callback; void runAfter(int time_in_ms, const Callback& cb); static Timer& instance(); // ... }; class Request { void send() { Timer::instance().runAfter( // cancel me 10s later 10*1000, boost::bind(&Request::cancel, this)); } void cancel(); }; blog.csdn.net/Solstice giantchen@gmail.com 40
  • 41. tr1::function and tr1::bind basics • tr1::function is a genetic functor which references to any callable things. • bind makes a function pointing to member functions of any class boost::function<void()> f; Foo* pFoo = new Foo; f = bind(&Foo::doit, pFoo); f(); // calls pFoo->doit() Bar bar; // possible bar is noncopyable f = bind(&Bar::dothat, boost::ref(bar)); f(); // calls bar.dothat() blog.csdn.net/Solstice giantchen@gmail.com 41
  • 42. A new methodology of interface/library design • function+bind = delegate in C#, Observer in Java • Get rid of inheritance, base class, hierarchy • Partial restriction on function signature, not on type or function name • A replacement of Strategy/Command pattern – And many OO behavioural design patterns • As fast as calling through member function pointer blog.csdn.net/Solstice giantchen@gmail.com 42
  • 43. A Thread class class Thread : boost::noncopyable { public: typedef boost::function<void()> Callback; Thread(Callback cb) : cb_(cb) { } void start() { /* some magic to call run() in new created thread */ } struct Foo private: { void run() { void run1(); cb_(); void run2(); } }; Callback cb_; // ... Foo foo; }; Thread thread1(boost::bind(&Foo::run1, &foo)); thread1.start(); Thread thread2(boost::bind(&Foo::run2, &foo)); thread2.start(); blog.csdn.net/Solstice giantchen@gmail.com 43
  • 44. Caveats • bind makes copy(-ies) of argument(s) – use boost::ref() when the object is noncopyable – shared_ptr tr1::function<void()> f; shared_ptr<Foo> pFoo(new Foo); f = bind(&Foo::doit, pFoo); // long life foo • bind also takes parameter placeholders void Foo::xyz(int); function<void(int)> f = bind(&Foo::xyz, pFoo, _1); f(42); // pFoo->xyz(42); vector<Foo> foos; for_each(foos.begin(), foos.end(), bind(&Foo::xyz, _1, 42)); // call Foo::xyz(42) on every objects in foos blog.csdn.net/Solstice giantchen@gmail.com 44
  • 45. Is Timer thread safe? • No, same issue as Observer • Unregisier in dtor does not work • To make it safe, either – the timer guarantee the object not deleted – check its aliveness before calling cancel() blog.csdn.net/Solstice giantchen@gmail.com 45
  • 46. Weak callback class Request : public enable_shared_from_this<Request> { static void timeoutCallback(boost::weak_ptr<Request> wkReq) { shared_ptr<Request> req(wkReq.lock()); if (req) { req->cancel(); } } void send() { Timer::instance().runAfter( // cancel me 10s later 10*1000, boost::bind(&Request::timeoutCallback, boost::weak_ptr<Request>(shared_from_this()))); } // ... blog.csdn.net/Solstice giantchen@gmail.com 46
  • 47. Boost signals? • Cons – Not thread safe – Not header only – auto unregister by inheriting trackable class • makes connecting multiple signals difficult • Update 2010 Jan: – Boost.signals2 is thread safe and header only – The rest of slides can be ignored blog.csdn.net/Solstice giantchen@gmail.com 47
  • 48. Our Signal • Synchronous, callback in the same thread • Auto disconnecting at destructing Slot – No base class requirement • Thread safe and race condition free • Contention free – None of the methods will be blocked for uncertain time blog.csdn.net/Solstice giantchen@gmail.com 48
  • 49. More take aways • Replace class inheritance with boost::function and boost::bind, especially when design interfaces or libraries • Copy-on-write for containers in signals, or data cache • Use weak_ptr to break cycles blog.csdn.net/Solstice giantchen@gmail.com 49
  • 50. Thanks! Q&A blog.csdn.net/Solstice giantchen@gmail.com blog.csdn.net/Solstice giantchen@gmail.com 50

Notas del editor

  1. In a real world, Counter should use atomic operations. Here for illustrating only.
  2. not fully constructed object
  3. worse, mutex_ itself is a member of x, which has already been destructed.
  4. Storing a raw pointer is bad
  5. after set proxy to 0, a write barrier is inserted, to flush the cache line.
  6. Deletion happens in the same thread as last shared_ptr goes out of scope, not necessary same thread of creation.
  7. A concrete exmample will be given in Part II, if we have enough time.
  8. shared_ptr&lt;void&gt;: captured destruction
  9. Show &amp;quot;tie&amp;quot; later
  10. Program design is data structure design But Signal is not on heap, so another layer of indirection needed.
  11. list on the left increase the ref count