67 #ifndef OIIO_THREAD_ALLOW_DCLP
68 # define OIIO_THREAD_ALLOW_DCLP 1
109 using std::recursive_mutex;
121 #if defined(__GNUC__)
123 #elif defined(_MSC_VER)
126 # error No yield on this platform.
136 #if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
137 for (
int i = 0; i < delay; ++i)
138 __asm__ __volatile__(
"pause;");
140 #elif defined(__GNUC__) && (defined(__arm__) || defined(__s390__))
141 for (
int i = 0; i < delay; ++i)
142 __asm__ __volatile__(
"NOP;");
144 #elif defined(_MSC_VER)
145 for (
int i = 0; i < delay; ++i) {
155 for (
int i = 0; i < delay; ++i)
167 , m_pausemax(pausemax)
173 if (m_count <= m_pausemax) {
235 #if OIIO_THREAD_ALLOW_DCLP
250 }
while (*(
volatile bool*)&m_locked);
262 m_locked.clear(std::memory_order_release);
269 return !m_locked.test_and_set(std::memory_order_acquire);
291 std::atomic_flag m_locked = ATOMIC_FLAG_INIT;
350 #if OIIO_THREAD_ALLOW_DCLP
351 while (*(
volatile int *)&m_readers > 0)
354 while (m_readers > 0)
380 class read_lock_guard {
393 class write_lock_guard {
442 int oldval = m_bits.fetch_add(1, std::memory_order_acquire);
443 if (!(oldval & WRITER))
447 int expected = (--m_bits) & NOTWRITER;
451 if (m_bits.compare_exchange_weak(expected, expected + 1,
452 std::memory_order_acquire))
457 expected = m_bits.load() & NOTWRITER;
458 }
while (!m_bits.compare_exchange_weak(expected, expected + 1,
459 std::memory_order_acquire));
469 m_bits.fetch_sub(1, std::memory_order_release);
478 if (m_bits.compare_exchange_weak(expected, WRITER,
479 std::memory_order_acquire))
485 }
while (!m_bits.compare_exchange_weak(expected, WRITER,
486 std::memory_order_acquire));
494 m_bits.fetch_sub(WRITER, std::memory_order_release);
526 enum { WRITER = 1<<30, NOTWRITER = WRITER-1 };
527 std::atomic<int> m_bits { 0 };
550 template<
class Mutex,
class Key,
class Hash,
size_t Bins = 16>
560 struct AlignedMutex {
564 AlignedMutex m_mutex[Bins];
581 m_threads.emplace_back(t);
585 template<
typename FUNC,
typename... Args>
596 for (
auto&
t : m_threads)
604 return m_threads.size();
608 mutable mutex m_mutex;
609 std::vector<std::unique_ptr<thread>> m_threads;
679 void resize(
int nthreads = -1);
690 template<
typename F>
auto push(F&&
f) -> std::future<decltype(f(0))>
692 auto pck = std::make_shared<std::packaged_task<decltype(f(0))(int)>>(
697 auto _f =
new std::function<void(int id)>(
698 [pck](
int id) { (*pck)(
id); });
699 push_queue_and_notify(_f);
701 return pck->get_future();
709 template<
typename F,
typename... Rest>
711 auto pck = std::make_shared<std::packaged_task<decltype(
f(0,
rest...))(
int)>>(
712 std::bind(std::forward<F>(
f), std::placeholders::_1, std::forward<Rest>(
rest)...)
717 auto _f =
new std::function<void(int id)>([pck](
int id) {
720 push_queue_and_notify (_f);
722 return pck->get_future();
736 bool this_thread_is_in_pool()
const;
751 size_t jobs_in_queue()
const;
759 bool very_busy()
const;
770 std::unique_ptr<Impl> m_impl;
773 void push_queue_and_notify(std::function<
void(
int id)>*
f);
809 , m_submitter_thread(std::this_thread::get_id())
826 std::this_thread::get_id() == submitter()
827 &&
"All tasks in a tast_set should be added by the same thread");
828 m_futures.emplace_back(std::move(
f));
836 void wait_for_task(
size_t taskindex,
bool block =
false);
842 void wait(
bool block =
false);
848 const std::chrono::milliseconds wait_time(0);
849 for (
auto&&
f : m_futures)
850 ASSERT(
f.wait_for(wait_time) == std::future_status::ready);
856 std::vector<std::future<void>> m_futures;
spin_mutex(const spin_mutex &)
void add_thread(thread *t)
std::lock_guard< mutex > lock_guard
*Note that the tasks the is the thread number *for the pool
spin_rw_mutex::write_lock_guard spin_rw_write_lock
lock_guard(spin_mutex &fm)
spin_mutex::lock_guard spin_lock
atomic_backoff(int pausemax=16)
size_t OIIO_API Hash(const char *s, size_t len)
read_lock_guard(spin_rw_mutex &fm)
write_lock_guard(spin_rw_mutex &fm)
OIIO_API thread_pool * default_thread_pool()
ImageBuf OIIO_API resize(const ImageBuf &src, string_view filtername="", float filterwidth=0.0f, ROI roi={}, int nthreads=0)
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
*Note that the tasks the is the thread number *for the or if it s being executed by a non pool thread(this *can happen in cases where the whole pool is occupied and the calling *thread contributes to running the work load).**Thread pool.Have fun
task_set(thread_pool *pool=nullptr)
Wrappers and utilities for atomics.
void push(std::future< void > &&f)
#define ASSERT(assertion, type, text)
auto push(F &&f, Rest &&...rest) -> std::future< decltype(f(0, rest...))>
const spin_rw_mutex & operator=(const spin_rw_mutex &)=delete
std::thread::id submitter() const
const spin_mutex & operator=(const spin_mutex &)
std::lock_guard< recursive_mutex > recursive_lock_guard
spin_rw_mutex::read_lock_guard spin_rw_read_lock
**If you just want to fire and args
auto push(F &&f) -> std::future< decltype(f(0))>
Mutex & operator[](const Key &key)
#define OIIO_NAMESPACE_END
GA_API const UT_StringHolder rest
thread * create_thread(FUNC func, Args &&...args)
*get result *(waiting if necessary)*A common idiom is to fire a bunch of sub tasks at the and then *wait for them to all complete We provide a helper task_set
#define OIIO_NAMESPACE_BEGIN