Linux (muduo network libraries): 04 --- Thread Synchronization summary of the (package MutexLock, MutexLockGuard, Condition)

  • In this article convergence in the previous article (mutex, a condition variable, read-write locks, semaphores, SLEEP) : https://blog.csdn.net/qq_41453285/article/details/104859230
  • MutexLock, MutexLockGuard, Condition class, etc. The complete code can be found in muduo / base in these class are not allowed to copy constructor and assignment

A, MutexLock, MutexLockGuard package

  • MutexLock: Packaging critical region (critical section), this is a simple resource with an exclusive package to create RAII techniques and destroyed. MutexLock general data members of another class
    • The critical zone on Windows struct CRITICAL_SECTION, is reentrant
    • Under Linux is pthread_mutex_t, default is not reentrant
  • MutexLockGuard: enter and exit the critical section of the package, namely locking and unlocking. MutexLockGuard general is on the stack object, its scope is exactly equal to the critical region

MutexLock

  • Description:
    • MutexLock added value in that it provides isLockedByThisThread () function for the program assertions
    • About tid () function, later in this article we will detail "Linux thread identifier"
  • code show as below:
class MutexLock :boost::noncopyable
{
public:
    MutexLock() :holder_(0)
    {
        pthread_mutex_init(&mutex_, NULL);
    }

    ~MutexLock()
    {
        assert(holder_ == 0);
        pthread_mutex_destory(&mutex_);
    }

    bool isLockByThisThread()
    {
        return holder_ == CurrentThread::tid();
    }

    void assertLocked()
    {
        assert(isLockByThisThread());
    }

    //仅供MutexLockGuard调用,严禁用户代码调用
    void lock()
    {
        //这两行顺序不能反
        pthread_mutex_lock(&mutex_);
        holder_ = CurrentThread::tid();
    }
    //仅供MutexLockGuard调用,严禁用户代码调用
    void unlock()
    {
        holder_ = 0;
        pthread_mutex_unlock(&mutex_);
    }

    //仅供Condition调用,严禁用户代码调用
    pthread_mutex_t* getPthreadMutex()
    {
        return &mutex_;
    }
private:
    pthread_mutex_t mutex_;
    pid_t holder_;
};

MutexLockGuard

  • code show as below:
class MutexLockGuard :boost::noncopyable
{
public:
    explicit MutexLockGuard(MutexLock& mutex):mutex_(mutex)
    {
        mutex_.lock();
    }

    ~MutexLockGuard()
    {
        mutex_.unlock();
    }
private:
    MutexLock& mutex_;
};

#define MutexLockGuard(x) static_assert(false,"missing mutex guard var name");
  •  Note that the above code is the last line defines a macro, the macro program in order to prevent such errors appear below:
void doit()
{
    //错误,产生一个临时对象,互斥器创建之后立马又销毁了,下面的临界区没有锁住
    MutexLockGuard(mutex);
    //正确的做法要加上变量名,例如:MutexLockGuard lock(mutex)
    
    //...临界区
}
  • Precautions:
    • Someone MutexLockGuard written template, where it did not do so because the template type parameter MutexLock only one possible , no need to arbitrarily increase flexibility, so I manually put the template instantiated (instantiate) a
    • In addition a more aggressive wording is, the lock / unlock into the private area, and then MutexLockGuard to friend MutexLock of. I think in comments to inform the programmer, the other before the check-in code review is also very easy to find cases of misuse (grep getPthreadMutex)
  • This code does not reach industrial strength:
    • mutex created PTHREAD_MUTEX_DEFAULT type, rather than we expected PTHREAD_MUTEX_NORMAL type (in fact, both are likely to be identical), a strict approach is to use mutexattr to indicate the type of the specified mutex (mutex attributes can be found in: HTTPS: // blog.csdn.net/qq_41453285/article/details/90904833 )
    • Do not check the return value. Here not () to check the return value assert, since assert () in the release build was empty statement . We check the return value meaning is to prevent deficiencies ENOMEM such resources, which generally occur in heavily loaded product program. Once this error, the program must be cleaned immediately and take the initiative to withdraw from the scene, otherwise it will somehow collapse, to the subsequent investigation difficult. Here we need to assert non-debug, perhaps google-glog the CHECK () macro is a good idea
  • Some other ideas:
    • One feature muduo library is only the most common and the most basic functions, in particular, it intends to avoid providing a variety of functions similar choice. muduo not a "grocery store" and would not indiscriminate white, to a variety of useful and useless features full swing put out. muduo Shanfanjiujian, shrugs; reducing choice, life simpler
    • MutexLock not provide trylock () function, because I have not used it in the generated code. I can not think when procedures need to "try to lock a lock," Maybe I wrote the code is too simple (use a trylock is used to observe lock contention, see [RWC] "Consider using nonblocking synchronization routines to monitor contention ")

Two, Condition package

  • Condition variable (condition variable) allows the wait () when the specified mutex
  • About why this class their own package Condition:
    • But I can not think of any reason why a condition variable will be used in conjunction with different mutex . Java's intrinsic condition Condition class and do not support, so I think we can give up this flexibility, honestly good one
    • Instead, boost :: thread of condition_variable mutex is specified at the time of wait, please visit the complex design of its synchronization primitives:
      • Concept有四种:Lockable、TimedLockable、SharedLockable、 UpgradeLockable
      • Lock有六种:lock_guard、unique_lock、shared_lock、 upgrade_lock、upgrade_to_unique_lock、scoped_try_lock
      • Mutex有七种:mutex、try_mutex、timed_mutex、 recursive_mutex、recursive_try_mutex、recursive_timed_mutex、 shared_mutex
    • I am afraid I stupid, to see such a fuss boost :: thread library, I had three bowed detour. Unfortunately C ++ threads library 11 also adopted this scheme . The class name is also does not make sense, why not be honest with popular names such readers_writer_lock it? Have to increase mental burden, he had invented a new name. I do not want to pay the price for such flexibility, would prefer to do a few simple to see to understand the class to use , "wheels" that a few simple lines of code made made it anyway. Of course, is the ability to provide flexibility, but the flexibility is not required where the code is written dead, more needs great wisdom

Condition

  • The following muduo :: Condition class simply encapsulates condition variable, it is also easy to use
  • About member function naming rules:
    • Here with notify / notifyAll as a function name, because there are other meanings signal, C ++ in the signal / slot, C and so on in the signalhandler
    • I do not think that the conflict, we own defines the name of these member functions
class Condition :boost::noncopyable
{
public:
    explicit Condition(MutexLock& mutex) :mutex_(mutex)
    {
        pthread_cond_init(&pcond_);
    }
	~Condition()
    {
        pthread_cond_destory(&pcond_);
    }

    void wait()
    {
        pthread_cond_wait(&pcond_, mutex_.getPthreadMutex());
    }
    void notify()
    {
        pthread_cond_signal(&pcond_);
    }
    void notifyAll()
    {
        pthread_cond_broadcast(&pcond_);
    }
private:
    MutexLock& mutex_;
    pthread_cond_t pcond_;
};

Use on condition variables and mutex's

  • If you want to include a class MutexLock and Condition, must pay attention to the order of their declaration and initialization sequence:
    • MutexLock construction should precede Condition
    • Condition to initialize and MutexLock
  • For example following a a CountDownLatch (countdown) class:
class CountDownLatch
{
public:
    //构造函数中,初始化顺序要与声明顺序一致
    //并且使用mutex_初始化conditon_
    CountDownLatch(MutexLock& mutex)
        :mutex_(mutex), conditon_(mutex_), count_(0) {}
private:
    MutexLock& mutex_;   //互斥器先于条件变量定义
    Condition conditon_;
    int count_;
};

Third, the summary

  • Let me stress again, although it took a lot of space in this chapter describes how to use mutex and condition variable properly, but it does not mean that I encourage use them everywhere:
    • Both are very low-level synchronization primitives , mainly used for more advanced concurrent programming tool
    • A multi-threaded programs to synchronize if heavy use mutex and condition variable, with basic pencil knife sawing trees (Meng Yan language) lacks distinction
  • In the program using the Pthreads library has an additional benefit: analysis tools recognize them, understand their semantics . Threading Analysis Tools such as Intel Thread Checker and Valgrind-Helgrind 33 and so be able to identify Pthreads calls, and according happens-before relationship (see: http://research.microsoft.com/en-us/um/people/lamport/pubs/time -clocks.pdf ) whether the data race analysis program

Fourth, additional

Released 1525 original articles · won praise 1084 · Views 450,000 +

Guess you like

Origin blog.csdn.net/qq_41453285/article/details/104875213