neuray API Programmer's Manual

lock.h File Reference

Description

Multithreading locks. See Multithreading Support.

Code Example

lock.h

‎/***************************************************************************************************
 * Copyright 2024 NVIDIA Corporation. All rights reserved.
 **************************************************************************************************/

#ifndef MI_BASE_LOCK_H
#define MI_BASE_LOCK_H

#include <cstdlib>

#include <mi/base/assert.h>
#include <mi/base/config.h>

#ifndef MI_PLATFORM_WINDOWS
#include <cerrno>
#include <pthread.h>
#else
#include <mi/base/miwindows.h>
#endif

namespace mi {

namespace base {










class Lock
{
public:
    Lock();

    ~Lock();

    class Block
    {
    public:
        explicit Block( Lock* lock = 0);

        ~Block();

        void set( Lock* lock);

        bool try_set( Lock* lock);

        void release();

    private:
        // The lock associated with this helper class.
        Lock* m_lock;
    };

protected:
    void lock();

    bool try_lock();

    void unlock();

private:
    // This class is non-copyable.
    Lock( Lock const &);

    // This class is non-assignable.
    Lock& operator=( Lock const &);

#ifndef MI_PLATFORM_WINDOWS
    // The mutex implementing the lock.
    pthread_mutex_t m_mutex;
#else
    // The critical section implementing the lock.
    SRWLOCK m_srwlock;
    // The flag used to ensure that the lock is non-recursive.
    bool m_locked;
#endif
};

class Recursive_lock
{
public:
    Recursive_lock();

    ~Recursive_lock();

    class Block
    {
    public:
        explicit Block( Recursive_lock* lock = 0);

        ~Block();

        void set( Recursive_lock* lock);

        bool try_set( Recursive_lock* lock);

        void release();

    private:
        // The lock associated with this helper class.
        Recursive_lock* m_lock;
    };

protected:
    void lock();

    bool try_lock();

    void unlock();

private:
    // This class is non-copyable.
    Recursive_lock( Recursive_lock const &);

    // This class is non-assignable.
    Recursive_lock& operator=( Recursive_lock const &);

#ifndef MI_PLATFORM_WINDOWS
    // The mutex implementing the lock.
    pthread_mutex_t m_mutex;
#else
    // The critical section implementing the lock.
    CRITICAL_SECTION m_critical_section;
#endif
};

#ifndef MI_FOR_DOXYGEN_ONLY

inline Lock::Lock()
#ifdef MI_PLATFORM_WINDOWS
  : m_srwlock( SRWLOCK_INIT),
    m_locked( false)
#endif
{
#ifndef MI_PLATFORM_WINDOWS
    pthread_mutexattr_t mutex_attributes;
    pthread_mutexattr_init( &mutex_attributes);
    pthread_mutexattr_settype( &mutex_attributes, PTHREAD_MUTEX_ERRORCHECK);
    pthread_mutex_init( &m_mutex, &mutex_attributes);
#endif
}

inline Lock::~Lock()
{
#ifndef MI_PLATFORM_WINDOWS
    int result = pthread_mutex_destroy( &m_mutex);
    // Avoid assertion here because it might be mapped to an exception.
    // mi_base_assert( result == 0);
    (void) result;
#else
    // Avoid assertion here because it might be mapped to an exception.
    // mi_base_assert( !m_locked);
#endif
}

inline void Lock::lock()
{
#ifndef MI_PLATFORM_WINDOWS
    int result = pthread_mutex_lock( &m_mutex);
    if( result == EDEADLK) {
        mi_base_assert( !"Dead lock");
        abort();
    }
#else
    AcquireSRWLockExclusive( &m_srwlock);
    if( m_locked) {
        mi_base_assert( !"Dead lock");
        abort();
    }
    m_locked = true;
#endif
}

inline bool Lock::try_lock()
{
#ifndef MI_PLATFORM_WINDOWS
    int result = pthread_mutex_trylock( &m_mutex);
    // Old glibc versions incorrectly return EDEADLK instead of EBUSY
    // (https://sourceware.org/bugzilla/show_bug.cgi?id=4392).
    mi_base_assert( result == 0 || result == EBUSY || result == EDEADLK);
    return result == 0;
#else
    BOOL result = TryAcquireSRWLockExclusive( &m_srwlock);
    if( result == FALSE)
        return false;
    if( m_locked) {
        ReleaseSRWLockExclusive( &m_srwlock);
        return false;
    }
    m_locked = true;
    return true;     
#endif
}

inline void Lock::unlock()
{
#ifndef MI_PLATFORM_WINDOWS
    int result = pthread_mutex_unlock( &m_mutex);
    mi_base_assert( result == 0);
    (void) result;
#else
    mi_base_assert( m_locked);
    m_locked = false;
    ReleaseSRWLockExclusive( &m_srwlock);
#endif
}

inline Lock::Block::Block( Lock* lock)
{
    m_lock = lock;
    if( m_lock)
        m_lock->lock();
}

inline Lock::Block::~Block()
{
    release();
}

inline void Lock::Block::set( Lock* lock)
{
    if( m_lock == lock)
        return;
    if( m_lock)
        m_lock->unlock();
    m_lock = lock;
    if( m_lock)
        m_lock->lock();
}

inline bool Lock::Block::try_set( Lock* lock)
{
    if( m_lock == lock)
        return true;
    if( m_lock)
        m_lock->unlock();
    m_lock = lock;
    if( m_lock && m_lock->try_lock())
        return true;
    m_lock = 0;
    return false;
}

inline void Lock::Block::release()
{
    if( m_lock) 
        m_lock->unlock();
    m_lock = 0;
}

inline Recursive_lock::Recursive_lock()
{
#ifndef MI_PLATFORM_WINDOWS
    pthread_mutexattr_t mutex_attributes;
    pthread_mutexattr_init( &mutex_attributes);
    pthread_mutexattr_settype( &mutex_attributes, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init( &m_mutex, &mutex_attributes);
#else
    InitializeCriticalSection( &m_critical_section);
#endif
}

inline Recursive_lock::~Recursive_lock()
{
#ifndef MI_PLATFORM_WINDOWS
    int result = pthread_mutex_destroy( &m_mutex);
    // Avoid assertion here because it might be mapped to an exception.
    // mi_base_assert( result == 0);
    (void) result;
#else
    DeleteCriticalSection( &m_critical_section);
#endif
}

inline void Recursive_lock::lock()
{
#ifndef MI_PLATFORM_WINDOWS
    int result = pthread_mutex_lock( &m_mutex);
    // Avoid assertion here because it might be mapped to an exception.
    // mi_base_assert( result == 0);
    (void) result;
#else
    EnterCriticalSection( &m_critical_section);
#endif
}

inline bool Recursive_lock::try_lock()
{
#ifndef MI_PLATFORM_WINDOWS
    int result = pthread_mutex_trylock( &m_mutex);
    mi_base_assert( result == 0 || result == EBUSY);
    return result == 0;
#else
    BOOL result = TryEnterCriticalSection( &m_critical_section);
    return result != 0;
#endif
}

inline void Recursive_lock::unlock()
{
#ifndef MI_PLATFORM_WINDOWS
    int result = pthread_mutex_unlock( &m_mutex);
    mi_base_assert( result == 0);
    (void) result;
#else
    LeaveCriticalSection( &m_critical_section);
#endif
}

inline Recursive_lock::Block::Block( Recursive_lock* lock)
{
    m_lock = lock;
    if( m_lock)
        m_lock->lock();
}

inline Recursive_lock::Block::~Block()
{
    release();
}

inline void Recursive_lock::Block::set( Recursive_lock* lock)
{
    if( m_lock == lock)
        return;
    if( m_lock)
        m_lock->unlock();
    m_lock = lock;
    if( m_lock)
        m_lock->lock();
}

inline bool Recursive_lock::Block::try_set( Recursive_lock* lock)
{
    if( m_lock == lock)
        return true;
    if( m_lock)
        m_lock->unlock();
    m_lock = lock;
    if( m_lock && m_lock->try_lock())
        return true;
    m_lock = 0;
    return false;
}

inline void Recursive_lock::Block::release()
{
    if( m_lock) 
        m_lock->unlock();
    m_lock = 0;
}

#endif // MI_FOR_DOXYGEN_ONLY
 // end group mi_base_threads

}  // namespace base

}  // namespace mi

#endif // MI_BASE_LOCK_H

Namespaces

namespace 
Common namespace for APIs of NVIDIA Advanced Rendering Center GmbH. More...
namespace 
Namespace for the Base API. More...

Classes

class 
Non-recursive lock class. More...
class 
Utility class to acquire a lock that is released by the destructor. More...
class 
Recursive lock class. More...
class 
Utility class to acquire a lock that is released by the destructor. More...