---
title: llarp/util/thread/threading.hpp

---

# llarp/util/thread/threading.hpp



## Namespaces

| Name           |
| -------------- |
| **[llarp](Namespaces/namespacellarp.md)** <br>[crypto.hpp] |
| **[llarp::util](Namespaces/namespacellarp_1_1util.md)**  |

## Classes

|                | Name           |
| -------------- | -------------- |
| struct | **[llarp::util::NullMutex](Classes/structllarp_1_1util_1_1NullMutex.md)** <br>a mutex that does nothing  |
| struct | **[llarp::util::NullLock](Classes/structllarp_1_1util_1_1NullLock.md)** <br>a lock that does nothing  |
| class | **[llarp::util::Semaphore](Classes/classllarp_1_1util_1_1Semaphore.md)**  |
| struct | **[llarp::util::ContentionKiller](Classes/structllarp_1_1util_1_1ContentionKiller.md)**  |

## Defines

|                | Name           |
| -------------- | -------------- |
|  | **[DECLARE_LOCK](Files/threading_8hpp.md#define-declare-lock)**(type, var, ...)  |




## Macros Documentation

### define DECLARE_LOCK

```cpp
#define DECLARE_LOCK(
    type,
    var,
    ...
)
type var __VA_ARGS__
```


## Source code

```cpp
#pragma once

#include <thread>
#include <shared_mutex>
#include <mutex>
#include <condition_variable>
#include <optional>

#include "annotations.hpp"

#include <iostream>
#include <thread>

#if defined(WIN32) && !defined(__GNUC__)
#include <process.h>
using pid_t = int;
#else
#include <sys/types.h>
#include <unistd.h>
#endif

#ifdef TRACY_ENABLE
#include <Tracy.hpp>
#define DECLARE_LOCK(type, var, ...) TracyLockable(type, var)
#else
#define DECLARE_LOCK(type, var, ...) type var __VA_ARGS__
#endif

namespace llarp
{
  namespace util
  {
    struct CAPABILITY("mutex") NullMutex
    {
#ifdef LOKINET_DEBUG
      mutable std::optional<std::thread::id> m_id;
      void
      lock() const
      {
        if (!m_id)
        {
          m_id = std::this_thread::get_id();
        }
        else if (*m_id != std::this_thread::get_id())
        {
          std::cerr << "NullMutex " << this << " was used across threads: locked by "
                    << std::this_thread::get_id() << " and was previously locked by " << *m_id
                    << "\n";
          // if you're encountering this abort() call, you may have discovered a
          // case where a NullMutex should be reverted to a "real mutex"
          std::abort();
        }
      }
#else
      void
      lock() const
      {}
#endif
      // Does nothing; once locked the mutex belongs to that thread forever
      void
      unlock() const
      {}
    };

    struct SCOPED_CAPABILITY NullLock
    {
      NullLock(NullMutex& mtx) ACQUIRE(mtx)
      {
        mtx.lock();
      }

      ~NullLock() RELEASE()
      {
        (void)this;  // trick clang-tidy
      }
    };

    using Mutex = std::shared_timed_mutex;

    using Lock = std::lock_guard<Mutex>;

    template <typename... Mutex>
    [[nodiscard]] auto
    unique_locks(Mutex&... lockables)
    {
      std::lock(lockables...);
      return std::make_tuple(std::unique_lock{lockables, std::adopt_lock}...);
    }

    class Semaphore
    {
     private:
      std::mutex m_mutex;  // protects m_count
      size_t m_count GUARDED_BY(m_mutex);
      std::condition_variable m_cv;

     public:
      Semaphore(size_t count) : m_count(count)
      {}

      void
      notify() EXCLUDES(m_mutex)
      {
        {
          std::lock_guard<std::mutex> lock(m_mutex);
          m_count++;
        }
        m_cv.notify_one();
      }

      void
      wait() EXCLUDES(m_mutex)
      {
        std::unique_lock lock{m_mutex};
        m_cv.wait(lock, [this] { return m_count > 0; });
        m_count--;
      }

      bool
      waitFor(std::chrono::microseconds timeout) EXCLUDES(m_mutex)
      {
        std::unique_lock lock{m_mutex};
        if (!m_cv.wait_for(lock, timeout, [this] { return m_count > 0; }))
          return false;

        m_count--;
        return true;
      }
    };

    void
    SetThreadName(const std::string& name);

    inline pid_t
    GetPid()
    {
#ifdef WIN32
      return _getpid();
#else
      return ::getpid();
#endif
    }

    // type for detecting contention on a resource
    struct ContentionKiller
    {
      template <typename F>
      void
      TryAccess(F visit) const
#if defined(LOKINET_DEBUG)
          EXCLUDES(_access)
#endif
      {
#if defined(LOKINET_DEBUG)
        NullLock lock(_access);
#endif
        visit();
      }
#if defined(LOKINET_DEBUG)
     private:
      mutable NullMutex _access;
#endif
    };
  }  // namespace util
}  // namespace llarp
```


-------------------------------

Updated on 2022-10-25 at 00:38:18 +0000
