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...