static threads::thread_state_enum thread_function(Address lva) { try { LTM_(debug) << "Executing component action(" << detail::get_action_name<Derived>() << ") lva(" << reinterpret_cast<void const*> (get_lva<Component>::call(lva)) << ")"; (get_lva<Component>::call(lva)->*F)(); // just call the function } catch (hpx::exception const& e) { if (e.get_error() != hpx::thread_interrupted) { LTM_(error) << "Unhandled exception while executing component action(" << detail::get_action_name<Derived>() << ") lva(" << reinterpret_cast<void const*> (get_lva<Component>::call(lva)) << "): " << e.what(); // report this error to the console in any case hpx::report_error(boost::current_exception()); } } // verify that there are no more registered locks for this OS-thread util::verify_no_locks(); return threads::terminated; }
BOOST_FORCEINLINE static threads::thread_state_enum thread_function(State) { try { LTM_(debug) << "Executing plain action(" << detail::get_action_name<Derived>() << ")."; F(); // call the function, ignoring the return value } catch (hpx::exception const& e) { if (e.get_error() != hpx::thread_interrupted) { LTM_(error) << "Unhandled exception while executing plain action(" << detail::get_action_name<Derived>() << "): " << e.what(); // report this error to the console in any case hpx::report_error(boost::current_exception()); } } catch (...) { LTM_(error) << "Unhandled exception while executing plain action(" << detail::get_action_name<Derived>() << ")"; // report this error to the console in any case hpx::report_error(boost::current_exception()); } // Verify that there are no more registered locks for this // OS-thread. This will throw if there are still any locks // held. util::force_error_on_lock(); return threads::terminated; }
BOOST_FORCEINLINE result_type operator()( HPX_ENUM_FWD_ARGS(N, Arg, arg)) const { try { LTM_(debug) << "Executing plain action(" << detail::get_action_name<Derived>() << ")."; // The arguments are moved here. This function is called from a // bound functor. In order to do true perfect forwarding in an // asynchronous operation. These bound variables must be moved // out of the bound object. // call the function, ignoring the return value F(HPX_ENUM_MOVE_ARGS(N, arg)); } catch (hpx::exception const& e) { if (e.get_error() != hpx::thread_interrupted) { LTM_(error) << "Unhandled exception while executing plain action(" << detail::get_action_name<Derived>() << "): " << e.what(); // report this error to the console in any case hpx::report_error(boost::current_exception()); } } // Verify that there are no more registered locks for this // OS-thread. This will throw if there are still any locks // held. util::force_error_on_lock(); return threads::terminated; }
static threads::thread_state_enum thread_function(State) { try { LTM_(debug) << "Executing plain action(" << detail::get_action_name<Derived>() << ")."; F(); // call the function, ignoring the return value } catch (hpx::exception const& e) { if (e.get_error() != hpx::thread_interrupted) { LTM_(error) << "Unhandled exception while executing plain action(" << detail::get_action_name<Derived>() << "): " << e.what(); // report this error to the console in any case hpx::report_error(boost::current_exception()); } } // verify that there are no more registered locks for this OS-thread util::verify_no_locks(); return threads::terminated; }
inline thread_state_enum set_active_state( thread_id_type const& thrd, thread_state_enum newstate, thread_state_ex_enum newstate_ex, thread_priority priority, thread_state previous_state) { if (HPX_UNLIKELY(!thrd)) { HPX_THROW_EXCEPTION(null_thread_id, "threads::detail::set_active_state", "NULL thread id encountered"); return terminated; } // make sure that the thread has not been suspended and set active again // in the mean time thread_state current_state = thrd->get_state(); if (thread_state_enum(current_state) == thread_state_enum(previous_state) && current_state != previous_state) { LTM_(warning) << "set_active_state: thread is still active, however " "it was non-active since the original set_state " "request was issued, aborting state change, thread(" << thrd.get() << "), description(" << thrd->get_description() << "), new state(" << get_thread_state_name(newstate) << ")"; return terminated; } // just retry, set_state will create new thread if target is still active error_code ec(lightweight); // do not throw detail::set_thread_state(thrd, newstate, newstate_ex, priority, std::size_t(-1), ec); return terminated; }
HPX_FORCEINLINE result_type operator()(threads::thread_state_ex_enum) { LTM_(debug) << "Executing " << Action::get_action_name(lva_) << " with continuation(" << cont_->get_id() << ")"; actions::trigger(*cont_, f_); return threads::terminated; }
BOOST_FORCEINLINE result_type operator()( naming::address::address_type lva, HPX_ENUM_FWD_ARGS(N, Arg, arg)) const { try { LTM_(debug) << "Executing component action(" << detail::get_action_name<Derived>() << ") lva(" << reinterpret_cast<void const*> (get_lva<Component>::call(lva)) << ")"; (get_lva<Component>::call(lva)->*F)( HPX_ENUM_FORWARD_ARGS(N, Arg, arg)); } catch (hpx::thread_interrupted const&) { /* swallow this exception */ } catch (hpx::exception const& e) { LTM_(error) << "Unhandled exception while executing component action(" << detail::get_action_name<Derived>() << ") lva(" << reinterpret_cast<void const*> (get_lva<Component>::call(lva)) << "): " << e.what(); // report this error to the console in any case hpx::report_error(boost::current_exception()); } catch (...) { LTM_(error) << "Unhandled exception while executing component action(" << detail::get_action_name<Derived>() << ") lva(" << reinterpret_cast<void const*> (get_lva<Component>::call(lva)) << ")"; // report this error to the console in any case hpx::report_error(boost::current_exception()); } // Verify that there are no more registered locks for this // OS-thread. This will throw if there are still any locks // held. util::force_error_on_lock(); return threads::terminated; }
BOOST_FORCEINLINE static util::unused_type execute_function(naming::address::address_type lva, Arguments &&) { LTM_(debug) << "base_action0::execute_function: name(" << detail::get_action_name<Derived>() << ") lva(" << reinterpret_cast<void const*>( get_lva<Component const>::call(lva)) << ")"; (get_lva<Component const>::call(lva)->*F)(); return util::unused; }
BOOST_FORCEINLINE static threads::thread_state_enum thread_function(Address lva) { try { LTM_(debug) << "Executing component action(" << detail::get_action_name<Derived>() << ") lva(" << reinterpret_cast<void const*> (get_lva<Component const>::call(lva)) << ")"; (get_lva<Component const>::call(lva)->*F)(); // just call the function } catch (hpx::thread_interrupted const&) { //-V565 /* swallow this exception */ } catch (hpx::exception const& e) { LTM_(error) << "Unhandled exception while executing component action(" << detail::get_action_name<Derived>() << ") lva(" << reinterpret_cast<void const*> (get_lva<Component const>::call(lva)) << "): " << e.what(); // report this error to the console in any case hpx::report_error(boost::current_exception()); } catch (...) { LTM_(error) << "Unhandled exception while executing component action(" << detail::get_action_name<Derived>() << ") lva(" << reinterpret_cast<void const*> (get_lva<Component const>::call(lva)) << ")"; // report this error to the console in any case hpx::report_error(boost::current_exception()); } // Verify that there are no more registered locks for this // OS-thread. This will throw if there are still any locks // held. util::force_error_on_lock(); return threads::terminated; }
/// This is a function which gets called periodically by the thread /// manager to allow for maintenance tasks to be executed in the /// scheduler. Returns true if the OS thread calling this function /// has to be terminated (i.e. no more work has to be done). virtual bool wait_or_add_new(std::size_t num_thread, bool running, std::int64_t& idle_loop_count) { std::size_t queues_size = this->queues_.size(); HPX_ASSERT(num_thread < queues_size); std::size_t added = 0; bool result = true; result = this->queues_[num_thread]->wait_or_add_new(running, idle_loop_count, added) && result; if (0 != added) return result; #ifdef HPX_HAVE_THREAD_MINIMAL_DEADLOCK_DETECTION // no new work is available, are we deadlocked? if (HPX_UNLIKELY(minimal_deadlock_detection && LHPX_ENABLED(error))) { bool suspended_only = true; for (std::size_t i = 0; suspended_only && i != queues_size; ++i) { suspended_only = this->queues_[i]->dump_suspended_threads( i, idle_loop_count, running); } if (HPX_UNLIKELY(suspended_only)) { if (running) { LTM_(error) //-V128 << "queue(" << num_thread << "): " << "no new work available, are we deadlocked?"; } else { LHPX_CONSOLE_(hpx::util::logging::level::error) //-V128 << " [TM] queue(" << num_thread << "): " << "no new work available, are we deadlocked?\n"; } } } #endif return result; }
BOOST_FORCEINLINE result_type operator()( continuation_type cont, Func const& func ) const { try { LTM_(debug) << "Executing action(" << detail::get_action_name<Action>() << ") with continuation(" << cont->get_gid() << ")"; func(); cont->trigger(); } catch (...) { cont->trigger_error(boost::current_exception()); } return threads::terminated; }
BOOST_FORCEINLINE result_type operator()(continuation_type cont, void (Object::* func)(), Object* obj ) const { try { LTM_(debug) << "Executing action(" << detail::get_action_name<derived_type>() << ") with continuation(" << cont->get_gid() << ")"; (obj->*func)(); cont->trigger(); } catch (...) { cont->trigger_error(boost::current_exception()); } return threads::terminated; }
/////////////////////////////////////////////////////////////////////// // add new threads if there is some amount of work available std::size_t add_new(boost::int64_t add_count, thread_queue* addfrom, std::unique_lock<mutex_type> &lk, bool steal = false) { HPX_ASSERT(lk.owns_lock()); if (HPX_UNLIKELY(0 == add_count)) return 0; std::size_t added = 0; task_description* task = 0; while (add_count-- && addfrom->new_tasks_.pop(task, steal)) { #ifdef HPX_HAVE_THREAD_QUEUE_WAITTIME if (maintain_queue_wait_times) { addfrom->new_tasks_wait_ += util::high_resolution_clock::now() - util::get<2>(*task); ++addfrom->new_tasks_wait_count_; } #endif --addfrom->new_tasks_count_; // measure thread creation time util::block_profiler_wrapper<add_new_tag> bp(add_new_logger_); // create the new thread threads::thread_init_data& data = util::get<0>(*task); thread_state_enum state = util::get<1>(*task); threads::thread_id_type thrd; create_thread_object(thrd, data, state, lk); delete task; // add the new entry to the map of all threads std::pair<thread_map_type::iterator, bool> p = thread_map_.insert(thrd); if (HPX_UNLIKELY(!p.second)) { HPX_THROW_EXCEPTION(hpx::out_of_memory, "threadmanager::add_new", "Couldn't add new thread to the thread map"); return 0; } ++thread_map_count_; // only insert the thread into the work-items queue if it is in // pending state if (state == pending) { // pushing the new thread into the pending queue of the // specified thread_queue ++added; schedule_thread(thrd.get()); } // this thread has to be in the map now HPX_ASSERT(thread_map_.find(thrd.get()) != thread_map_.end()); HPX_ASSERT(thrd->get_pool() == &memory_pool_); } if (added) { LTM_(debug) << "add_new: added " << added << " tasks to queues"; //-V128 } return added; }
/// This is a function which gets called periodically by the thread /// manager to allow for maintenance tasks to be executed in the /// scheduler. Returns true if the OS thread calling this function /// has to be terminated (i.e. no more work has to be done). virtual bool wait_or_add_new(std::size_t num_thread, bool running, std::int64_t& idle_loop_count) { std::size_t added = 0; bool result = true; std::size_t high_priority_queues = high_priority_queues_.size(); thread_queue_type* this_high_priority_queue = nullptr; thread_queue_type* this_queue = queues_[num_thread]; if (num_thread < high_priority_queues) { this_high_priority_queue = high_priority_queues_[num_thread]; result = this_high_priority_queue->wait_or_add_new(running, idle_loop_count, added) && result; if (0 != added) return result; } result = this_queue->wait_or_add_new( running, idle_loop_count, added) && result; if (0 != added) return result; for (std::size_t idx: victim_threads_[num_thread]) { HPX_ASSERT(idx != num_thread); if (idx < high_priority_queues && num_thread < high_priority_queues) { thread_queue_type* q = high_priority_queues_[idx]; result = this_high_priority_queue-> wait_or_add_new(running, idle_loop_count, added, q) && result; if (0 != added) { q->increment_num_stolen_from_staged(added); this_high_priority_queue-> increment_num_stolen_to_staged(added); return result; } } result = this_queue->wait_or_add_new(running, idle_loop_count, added, queues_[idx]) && result; if (0 != added) { queues_[idx]->increment_num_stolen_from_staged(added); this_queue->increment_num_stolen_to_staged(added); return result; } } #ifdef HPX_HAVE_THREAD_MINIMAL_DEADLOCK_DETECTION // no new work is available, are we deadlocked? if (HPX_UNLIKELY(minimal_deadlock_detection && LHPX_ENABLED(error))) { bool suspended_only = true; for (std::size_t i = 0; suspended_only && i != queues_.size(); ++i) { suspended_only = queues_[i]->dump_suspended_threads( i, idle_loop_count, running); } if (HPX_UNLIKELY(suspended_only)) { if (running) { LTM_(error) //-V128 << "queue(" << num_thread << "): " << "no new work available, are we deadlocked?"; } else { LHPX_CONSOLE_(hpx::util::logging::level::error) //-V128 << " [TM] " //-V128 << "queue(" << num_thread << "): " << "no new work available, are we deadlocked?\n"; } } } #endif result = low_priority_queue_.wait_or_add_new(running, idle_loop_count, added) && result; if (0 != added) return result; return result; }
inline void create_thread( policies::scheduler_base* scheduler, thread_init_data& data, threads::thread_id_type& id, thread_state_enum initial_state = pending, bool run_now = true, error_code& ec = throws) { // verify parameters switch (initial_state) { case pending: case pending_do_not_schedule: case suspended: break; default: { std::ostringstream strm; strm << "invalid initial state: " << get_thread_state_name(initial_state); HPX_THROWS_IF(ec, bad_parameter, "threads::detail::create_thread", strm.str()); return; } } #ifdef HPX_HAVE_THREAD_DESCRIPTION if (!data.description) { HPX_THROWS_IF(ec, bad_parameter, "threads::detail::create_thread", "description is nullptr"); return; } #endif thread_self* self = get_self_ptr(); #ifdef HPX_HAVE_THREAD_PARENT_REFERENCE if (nullptr == data.parent_id) { if (self) { data.parent_id = threads::get_self_id().get(); data.parent_phase = self->get_thread_phase(); } } if (0 == data.parent_locality_id) data.parent_locality_id = get_locality_id(); #endif if (nullptr == data.scheduler_base) data.scheduler_base = scheduler; // Pass critical priority from parent to child. if (self) { if (thread_priority_critical == threads::get_self_id()->get_priority()) data.priority = thread_priority_critical; } // create the new thread std::size_t num_thread = data.num_os_thread; scheduler->create_thread(data, &id, initial_state, run_now, ec, num_thread); LTM_(info) << "register_thread(" << id << "): initial_state(" << get_thread_state_name(initial_state) << "), " << "run_now(" << (run_now ? "true" : "false") #ifdef HPX_HAVE_THREAD_DESCRIPTION << "), description(" << data.description #endif << ")"; // potentially wake up waiting thread scheduler->do_some_work(num_thread); }
bool dump_suspended_threads(std::size_t num_thread, Map& tm, boost::int64_t& idle_loop_count, bool running) { #ifndef HPX_THREAD_MINIMAL_DEADLOCK_DETECTION HPX_UNUSED(tm); HPX_UNUSED(idle_loop_count); HPX_UNUSED(running); //-V601 return false; #else if (!minimal_deadlock_detection) return false; if (HPX_LIKELY(idle_loop_count++ < HPX_IDLE_LOOP_COUNT_MAX)) return false; // reset idle loop count idle_loop_count = 0; bool result = false; bool collect_suspended = true; bool logged_headline = false; typename Map::const_iterator end = tm.end(); for (typename Map::const_iterator it = tm.begin(); it != end; ++it) { threads::thread_data const* thrd = (*it).get(); threads::thread_state state = thrd->get_state(); threads::thread_state marked_state = thrd->get_marked_state(); if (state != marked_state) { // log each thread only once if (!logged_headline) { if (running) { LTM_(error) //-V128 << "Listing suspended threads while queue (" << num_thread << ") is empty:"; } else { LHPX_CONSOLE_(hpx::util::logging::level::error) //-V128 << " [TM] Listing suspended threads while queue (" << num_thread << ") is empty:\n"; } logged_headline = true; } if (running) { LTM_(error) << "queue(" << num_thread << "): " //-V128 << get_thread_state_name(state) << "(" << std::hex << std::setw(8) << std::setfill('0') << (*it).get() << "." << std::hex << std::setw(2) << std::setfill('0') << thrd->get_thread_phase() << "/" << std::hex << std::setw(8) << std::setfill('0') << thrd->get_component_id() << ")" #ifdef HPX_HAVE_THREAD_PARENT_REFERENCE << " P" << std::hex << std::setw(8) << std::setfill('0') << thrd->get_parent_thread_id() #endif << ": " << thrd->get_description() << ": " << thrd->get_lco_description(); } else { LHPX_CONSOLE_(hpx::util::logging::level::error) << " [TM] " //-V128 << "queue(" << num_thread << "): " << get_thread_state_name(state) << "(" << std::hex << std::setw(8) << std::setfill('0') << (*it).get() << "." << std::hex << std::setw(2) << std::setfill('0') << thrd->get_thread_phase() << "/" << std::hex << std::setw(8) << std::setfill('0') << thrd->get_component_id() << ")" #ifdef HPX_HAVE_THREAD_PARENT_REFERENCE << " P" << std::hex << std::setw(8) << std::setfill('0') << thrd->get_parent_thread_id() #endif << ": " << thrd->get_description() << ": " << thrd->get_lco_description() << "\n"; } thrd->set_marked_state(state); // result should be true if we found only suspended threads if (collect_suspended) { switch(state.get_state()) { case threads::suspended: result = true; // at least one is suspended break; case threads::pending: case threads::active: result = false; // one is active, no deadlock (yet) collect_suspended = false; break; default: // If the thread is terminated we don't care too much // anymore. break; } } } } return result; #endif }
inline thread_state set_thread_state( thread_id_type const& thrd, thread_state_enum new_state, thread_state_ex_enum new_state_ex, thread_priority priority, std::size_t thread_num, error_code& ec) { if (HPX_UNLIKELY(!thrd)) { HPX_THROWS_IF(ec, null_thread_id, "threads::detail::set_thread_state", "NULL thread id encountered"); return thread_state(unknown); } // set_state can't be used to force a thread into active state if (new_state == threads::active) { std::ostringstream strm; strm << "invalid new state: " << get_thread_state_name(new_state); HPX_THROWS_IF(ec, bad_parameter, "threads::detail::set_thread_state", strm.str()); return thread_state(unknown); } // we know that the id is actually the pointer to the thread if (!thrd) { if (&ec != &throws) ec = make_success_code(); return thread_state(terminated); // this thread has already been terminated } thread_state previous_state; do { // action depends on the current state previous_state = thrd->get_state(); thread_state_enum previous_state_val = previous_state; // nothing to do here if the state doesn't change if (new_state == previous_state_val) { LTM_(warning) << "set_thread_state: old thread state is the same as new " "thread state, aborting state change, thread(" << thrd.get() << "), description(" << thrd->get_description() << "), new state(" << get_thread_state_name(new_state) << ")"; if (&ec != &throws) ec = make_success_code(); return thread_state(new_state); } // the thread to set the state for is currently running, so we // schedule another thread to execute the pending set_state switch (previous_state_val) { case active: { // schedule a new thread to set the state LTM_(warning) << "set_thread_state: thread is currently active, scheduling " "new thread, thread(" << thrd.get() << "), description(" << thrd->get_description() << "), new state(" << get_thread_state_name(new_state) << ")"; thread_init_data data( boost::bind(&set_active_state, thrd, new_state, new_state_ex, priority, previous_state), "set state for active thread", 0, priority); create_work(thrd->get_scheduler_base(), data, pending, ec); if (&ec != &throws) ec = make_success_code(); return previous_state; // done } break; case terminated: { LTM_(warning) << "set_thread_state: thread is terminated, aborting state " "change, thread(" << thrd.get() << "), description(" << thrd->get_description() << "), new state(" << get_thread_state_name(new_state) << ")"; if (&ec != &throws) ec = make_success_code(); // If the thread has been terminated while this set_state was // pending nothing has to be done anymore. return previous_state; } break; case pending: if (suspended == new_state) { // we do not allow explicit resetting of a state to suspended // without the thread being executed. std::ostringstream strm; strm << "set_thread_state: invalid new state, can't demote a " "pending thread, " << "thread(" << thrd.get() << "), description(" << thrd->get_description() << "), new state(" << get_thread_state_name(new_state) << ")"; LTM_(fatal) << strm.str(); HPX_THROWS_IF(ec, bad_parameter, "threads::detail::set_thread_state", strm.str()); return thread_state(unknown); } break; case suspended: break; // fine, just set the new state default: HPX_ASSERT(false); // should not happen break; } // If the previous state was pending we are supposed to remove the // thread from the queue. But in order to avoid linearly looking // through the queue we defer this to the thread function, which // at some point will ignore this thread by simply skipping it // (if it's not pending anymore). LTM_(info) << "set_thread_state: thread(" << thrd.get() << "), " "description(" << thrd->get_description() << "), " "new state(" << get_thread_state_name(new_state) << "), " "old state(" << get_thread_state_name(previous_state_val) << ")"; // So all what we do here is to set the new state. if (thrd->restore_state(new_state, previous_state)) { thrd->set_state_ex(new_state_ex); break; } // state has changed since we fetched it from the thread, retry LTM_(error) << "set_thread_state: state has been changed since it was fetched, " "retrying, thread(" << thrd.get() << "), " "description(" << thrd->get_description() << "), " "new state(" << get_thread_state_name(new_state) << "), " "old state(" << get_thread_state_name(previous_state_val) << ")"; } while (true); if (new_state == pending) { // REVIEW: Passing a specific target thread may interfere with the // round robin queuing. thrd->get_scheduler_base()->schedule_thread(thrd.get(), thread_num, priority); thrd->get_scheduler_base()->do_some_work(thread_num); } if (&ec != &throws) ec = make_success_code(); return previous_state; }
bool thread_pool<Scheduler>::run(boost::unique_lock<boost::mutex>& l, std::size_t num_threads) { HPX_ASSERT(l.owns_lock()); LTM_(info) //-V128 << "thread_pool::run: " << pool_name_ << " number of processing units available: " //-V128 << threads::hardware_concurrency(); LTM_(info) //-V128 << "thread_pool::run: " << pool_name_ << " creating " << num_threads << " OS thread(s)"; //-V128 if (0 == num_threads) { HPX_THROW_EXCEPTION(bad_parameter, "thread_pool::run", "number of threads is zero"); } #if defined(HPX_HAVE_THREAD_CUMULATIVE_COUNTS) && \ defined(HPX_HAVE_THREAD_IDLE_RATES) // scale timestamps to nanoseconds boost::uint64_t base_timestamp = util::hardware::timestamp(); boost::uint64_t base_time = util::high_resolution_clock::now(); boost::uint64_t curr_timestamp = util::hardware::timestamp(); boost::uint64_t curr_time = util::high_resolution_clock::now(); while ((curr_time - base_time) <= 100000) { curr_timestamp = util::hardware::timestamp(); curr_time = util::high_resolution_clock::now(); } if (curr_timestamp - base_timestamp != 0) { timestamp_scale_ = double(curr_time - base_time) / double(curr_timestamp - base_timestamp); } LTM_(info) << "thread_pool::run: " << pool_name_ << " timestamp_scale: " << timestamp_scale_; //-V128 #endif if (!threads_.empty() || sched_.has_reached_state(state_running)) return true; // do nothing if already running executed_threads_.resize(num_threads); executed_thread_phases_.resize(num_threads); tfunc_times_.resize(num_threads); exec_times_.resize(num_threads); try { HPX_ASSERT(startup_.get() == 0); startup_.reset( new boost::barrier(static_cast<unsigned>(num_threads+1)) ); // run threads and wait for initialization to complete sched_.set_all_states(state_running); topology const& topology_ = get_topology(); std::size_t thread_num = num_threads; while (thread_num-- != 0) { threads::mask_cref_type mask = sched_.Scheduler::get_pu_mask(topology_, thread_num); LTM_(info) //-V128 << "thread_pool::run: " << pool_name_ << " create OS thread " << thread_num //-V128 << ": will run on processing units within this mask: " #if !defined(HPX_WITH_MORE_THAN_64_THREADS) || \ (defined(HPX_HAVE_MAX_CPU_COUNT) && HPX_HAVE_MAX_CPU_COUNT <= 64) << std::hex << "0x" << mask; #else << "0b" << mask; #endif // create a new thread threads_.push_back(new boost::thread( util::bind(&thread_pool::thread_func, this, thread_num, boost::ref(topology_), boost::ref(*startup_)) )); // set the new threads affinity (on Windows systems) if (any(mask)) { error_code ec(lightweight); topology_.set_thread_affinity_mask(threads_.back(), mask, ec); if (ec) { LTM_(warning) //-V128 << "thread_pool::run: " << pool_name_ << " setting thread affinity on OS thread " //-V128 << thread_num << " failed with: " << ec.get_message(); } } else { LTM_(debug) //-V128 << "thread_pool::run: " << pool_name_ << " setting thread affinity on OS thread " //-V128 << thread_num << " was explicitly disabled."; } } // the main thread needs to have a unique thread_num init_tss(num_threads); startup_->wait(); }
inline threads::thread_id_type create_thread( policies::scheduler_base* scheduler, thread_init_data& data, thread_state_enum initial_state = pending, bool run_now = true, error_code& ec = throws) { // verify parameters switch (initial_state) { case pending: case suspended: break; default: { hpx::util::osstream strm; strm << "invalid initial state: " << get_thread_state_name(initial_state); HPX_THROWS_IF(ec, bad_parameter, "threads::detail::create_thread", hpx::util::osstream_get_string(strm)); return invalid_thread_id; } } #if HPX_THREAD_MAINTAIN_DESCRIPTION if (0 == data.description) { HPX_THROWS_IF(ec, bad_parameter, "threads::detail::create_thread", "description is NULL"); return invalid_thread_id; } #endif #if HPX_THREAD_MAINTAIN_PARENT_REFERENCE if (0 == data.parent_id) { thread_self* self = get_self_ptr(); if (self) { data.parent_id = threads::get_self_id().get(); data.parent_phase = self->get_thread_phase(); } } if (0 == data.parent_locality_id) data.parent_locality_id = get_locality_id(); #endif if (0 == data.scheduler_base) data.scheduler_base = scheduler; // create the new thread thread_id_type newid = scheduler->create_thread( data, initial_state, run_now, ec, data.num_os_thread); LTM_(info) << "register_thread(" << newid << "): initial_state(" << get_thread_state_name(initial_state) << "), " << "run_now(" << (run_now ? "true" : "false") #if HPX_THREAD_MAINTAIN_DESCRIPTION << "), description(" << data.description #endif << ")"; return newid; }