18#ifndef LIBMESH_THREADS_PTHREAD_H
19#define LIBMESH_THREADS_PTHREAD_H
23#ifndef LIBMESH_SQUASH_HEADER_WARNING
24# warning "This file is designed to be included through libmesh/threads.h"
27#ifdef LIBMESH_HAVE_PTHREAD
30#ifdef LIBMESH_HAVE_CXX11_THREAD
43# include <libkern/OSAtomic.h>
48#ifdef LIBMESH_HAVE_CXX11_THREAD
49# define LIBMESH_TLS_TYPE(type) thread_local type
50# define LIBMESH_TLS_REF(value) (value)
52# define LIBMESH_TLS_TYPE(type) type
53# define LIBMESH_TLS_REF(value) (value)
63#ifdef LIBMESH_HAVE_CXX11_THREAD
74typedef NonConcurrentThread
Thread;
184 pthread_mutexattr_init(&
attr);
185 pthread_mutexattr_settype(&
attr, PTHREAD_MUTEX_RECURSIVE);
213template <
typename Range>
217 std::size_t mn = std::min((std::size_t)requested, range.size()/range.grainsize());
218 return mn > 0 ? cast_int<unsigned int>(mn) : 1;
221template <
typename Range,
typename Body>
229template <
typename Range,
typename Body>
234 Body & body = *range_body->
body;
235 Range & range = *range_body->
range;
245class task_scheduler_init
269template <
typename Range,
typename Body>
271void parallel_for (
const Range & range,
const Body & body,
275 "Requested n_threads (" <<
n_threads <<
") exceeds the "
282 if (actual_threads == 1)
290 DisablePerfLogInScope disable_perf;
292 std::vector<std::unique_ptr<Range>> ranges(actual_threads);
293 std::vector<RangeBody<const Range, const Body>> range_bodies(actual_threads);
294 std::vector<pthread_t> threads(actual_threads);
297 std::size_t range_size = range.size() / actual_threads;
299 typename Range::const_iterator current_beginning = range.begin();
301 for (
unsigned int i=0; i<actual_threads; i++)
303 std::size_t this_range_size = range_size;
305 if (i+1 == actual_threads)
306 this_range_size += range.size() % actual_threads;
308 ranges[i] = std::make_unique<Range>(range, current_beginning, current_beginning + this_range_size);
310 current_beginning = current_beginning + this_range_size;
314 for (
unsigned int i=0; i<actual_threads; i++)
316 range_bodies[i].range = ranges[i].get();
317 range_bodies[i].body = &body;
324#ifdef LIBMESH_HAVE_OPENMP
329#pragma omp parallel for schedule (static) num_threads(actual_threads)
331 for (
int i=0; i<static_cast<int>(actual_threads); i++)
333#if !LIBMESH_HAVE_OPENMP
334 pthread_create(&threads[i],
nullptr, &run_body<Range, Body>, (
void *)&range_bodies[i]);
336 run_body<Range, Body>((
void *)&range_bodies[i]);
340#if !LIBMESH_HAVE_OPENMP
349 for (
int i=0; i<static_cast<int>(actual_threads); i++)
350 pthread_join(threads[i],
nullptr);
358template <
typename Range,
typename Body,
typename Partitioner>
360void parallel_for (
const Range & range,
const Body & body,
const Partitioner &,
370template <
typename Range,
typename Body>
376 "Requested n_threads (" <<
n_threads <<
") exceeds the "
383 if (actual_threads == 1)
391 DisablePerfLogInScope disable_perf;
393 std::vector<std::unique_ptr<Range>> ranges(actual_threads);
394 std::vector<std::unique_ptr<Body>> managed_bodies(actual_threads);
395 std::vector<Body *> bodies(actual_threads);
396 std::vector<RangeBody<Range, Body>> range_bodies(actual_threads);
400 for (
unsigned int i=1; i<actual_threads; i++)
401 managed_bodies[i] = std::make_unique<Body>(body, Threads::split());
406 for (
unsigned int i=1; i<actual_threads; i++)
407 bodies[i] = managed_bodies[i].
get();
410 std::size_t range_size = range.size() / actual_threads;
412 typename Range::const_iterator current_beginning = range.begin();
414 for (
unsigned int i=0; i<actual_threads; i++)
416 std::size_t this_range_size = range_size;
418 if (i+1 == actual_threads)
419 this_range_size += range.size() % actual_threads;
421 ranges[i] = std::make_unique<Range>(range, current_beginning, current_beginning + this_range_size);
423 current_beginning = current_beginning + this_range_size;
427 for (
unsigned int i=0; i<actual_threads; i++)
429 range_bodies[i].range = ranges[i].get();
430 range_bodies[i].body = bodies[i];
434 std::vector<pthread_t> threads(actual_threads);
439#ifdef LIBMESH_HAVE_OPENMP
444#pragma omp parallel for schedule (static) num_threads(actual_threads)
452 for (
int i=0; i<static_cast<int>(actual_threads); i++)
454#if !LIBMESH_HAVE_OPENMP
455 pthread_create(&threads[i],
nullptr, &run_body<Range, Body>, (
void *)&range_bodies[i]);
457 run_body<Range, Body>((
void *)&range_bodies[i]);
461#if !LIBMESH_HAVE_OPENMP
463 for (
unsigned int i=0; i<actual_threads; i++)
464 pthread_join(threads[i],
nullptr);
468 for (
unsigned int i=actual_threads-1; i != 0; i--)
470 bodies[i-1]->join(*bodies[i]);
473 managed_bodies[i].reset();
481template <
typename Range,
typename Body,
typename Partitioner>
483void parallel_reduce (
const Range & range, Body & body,
const Partitioner &,
499 operator T () {
return val; }
503 spin_mutex::scoped_lock lock(
smutex);
510 spin_mutex::scoped_lock lock(
smutex);
518 spin_mutex::scoped_lock lock(
smutex);
525 spin_mutex::scoped_lock lock(
smutex);
532 spin_mutex::scoped_lock lock(
smutex);
539 spin_mutex::scoped_lock lock(
smutex);
546 spin_mutex::scoped_lock lock(
smutex);
553 spin_mutex::scoped_lock lock(
smutex);
Defines atomic operations which can only be executed on a single thread at a time.
atomic< T > & operator=(const atomic< T > &value)
void acquire(recursive_mutex &in_rmutex)
scoped_lock(recursive_mutex &in_rmutex)
scoped_lock(spin_mutex &in_smutex)
void acquire(spin_mutex &in_smutex)
void initialize(int=automatic)
static const int automatic
task_scheduler_init(int=automatic)
const Elem & get(const ElemType type_in)
bool in_threads
A boolean which is true iff we are in a Threads:: function It may be useful to assert(!...
int active_threads
An integer which is set to the number of active threads when we are in a Threads:: parallel operation...
void * run_body(void *args)
tbb::spin_mutex spin_mutex
Spin mutex.
NonConcurrentThread Thread
Use the non-concurrent placeholder.
void parallel_reduce(const Range &range, Body &body, unsigned int n_threads=libMesh::n_threads())
Execute the provided reduction operation in parallel on the specified range.
RAIIAcquire< bool, true, true > BoolAcquire
void parallel_for(const Range &range, const Body &body, unsigned int n_threads=libMesh::n_threads())
Execute the provided function object in parallel on the specified range.
unsigned int num_pthreads(const Range &range, unsigned int requested=libMesh::n_threads())
The libMesh namespace provides an interface to certain functionality in the library.