C++ Creating an atomic function

2019-06-24 14:39发布

问题:

void foo ( Bar* bar , void(Bar::*qux)(void) )
{
    if ( bar )
    {
        bar->qux();
    }
}

The problem is:

  1. bar can be deleted after the check by another thread.

  2. I can not add a mutex member to Bar in order to lock it.

Thus I wonder, if I can tell the processor to run this function atomically, and how would I do so? I've spent way to much time on Google, but found no understandable manuals...

P.S. Debian, gcc , Boost NOT allowed, C++11 IS allowed.

回答1:

The concept of atomic methods doesnt exist in C++ like it does in Java, where you can define a method as synchronized. The closest you can get to that in C++ would be to create a ScopedMutex class as follows:

class ScopedMutex {
public:
    ScopedMutex(pthread_mutex *m) : theMutex_(m) {pthread_mutex_lock(theMutex_);}
    ~ScopedMutex() { pthread_mutex_unlock(theMutex_); }
    // Add appropriate copy constructors and operator=() to disallow mutex copy
    // Or consider passing in a reference
private:
    pthread_mutex *theMutex_;
};

Then use it like this in your function:

void foo ( Bar* bar , void(Bar::*qux)(void) )
{
    ScopedMutex m(&aMutex); // This mutex must be defined/initialized elsewhere

    if ( bar )
    {
        bar->qux();
    }

    // The ScopedMutex goes out of scope when the function does,
    // thus releasing the lock
}

But this wont do you any good unless you use the same mutex in every other method that uses the bar object.

Scoped Mutex are especially useful when you have a function with complicated logic where there are several return statements, so you dont have to manually unlock the mutex it will be unlocked when the function goes out of scope.



回答2:

You probably want to use a smart pointer with shared ownership semantics (e.g. shared_ptr, intrusive_ptr) to make sure the object stays alive as long as you refer to it.



回答3:

You want to temporarily share ownership of the object, in order to prevent another thread from deleting it. This is a job for shared_ptr, using weak_ptr to allow deletion when we don't need to access it:

void foo ( std::weak_ptr<Bar> weak_bar , void(Bar::*qux)(void) ) 
{
    if (std::shared_ptr<Bar> bar = weak_bar.lock())
    {
        // We now share ownership of the object - it won't be deleted
        bar->qux();
    }

    // We have released ownership - it can now be deleted
}

Of course, you still need synchronisation if multiple threads need to access the object; this only solves the problem of deletion specified in the question.



回答4:

Sorry, but no. C++ doesn't have anything to support that. You don't necessarily need to add the mutex to Bar, but to avoid it, you'll probably need a wrapper around Bar, or something on that order.



回答5:

I too have a requirement for executing 2 functions atomically in Thread-1.

Main Thread:

   CMythread* pThread = GetThreadFromPool();
   //allocate work to thread
   pThread->ResumeThread();

Thread-1:

 AddtoThreadPool(this);
 SuspendThread(); //sleep infinitely unless awakened by Main Thread

Problem: Main Thread can resume the thread in the pool before it is suspended and Thread-1 (pool thread) can suspend itself infinitely.

Solution: 1. Execute the 2 functions in the Thread-1 atomically. No amount of protection will work. 2. Periodically check the thread pool to resume a suspended thread that was allocated work.

Thanks for your answers.

Ajay