290 likes | 626 Views
POSIX threads and C++ facilities. Jakub Yaghob. Low-level threading and synchronization support. Pthreads POSIX threads IEEE POSIX 1003.1c (1995) C library All POSIX compliant systems (even Windows) ISO C++ 2011 Standard libraries New compilers Currently only partial support.
E N D
POSIX threads and C++ facilities Jakub Yaghob
Low-level threading and synchronization support • Pthreads • POSIX threads • IEEE POSIX 1003.1c (1995) • C library • All POSIX compliant systems (even Windows) • ISO C++ 2011 • Standard libraries • New compilers • Currently only partial support
Pthreads overview • Thread management • Thread attributes • Mutexes • Condition variables • Synchronization • R/W locks, barriers
Threads • Create • attr==NULL – default attributes int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); • Exit • Return value_ptr to join void pthread_exit(void *value_ptr); • Join • Suspend calling thread and wait for exit int pthread_join(pthread_t thread, void **value_ptr);
Threads – joinable, detached • Joinable • Only joinable threads can be joined • Should be by default joinable • Explicitly set joinability for greater compatibility • Detached • Explicitly set by attributes • Cannot be joined • Some resources can be spared
Threads – misc • Get my ID pthread_t pthread_self(void); • Compare thread IDs int pthread_equal(pthread_t t1, pthread_t t2); • Initialize once int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)); pthread_once_t once_control = PTHREAD_ONCE_INIT; • Kill int pthread_kill(pthread_t thread, int sig);
Thread attributes • Initialize attributes int pthread_attr_init(pthread_attr_t *attr); • Destroy attributes int pthread_attr_destroy(pthread_attr_t *attr); • Set/get int pthread_attr_getXXX(const pthread_attr_t *attr, TTT *av); int pthread_attr_setXXX(pthread_attr_t *attr, TTT av);
Thread attributes – examples • Joinable/detached • XXX = detachstate, TTT = int, av = PTHREAD_CREATE_DETACHED or PTHREAD_CREATE_JOINABLE • Stack • XXX = stacksize, TTT = size_t • XXX = stackaddr, TTT = void* • Scheduling • inheritsched, schedparam, schedpolicy
Mutexes • Create int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); • Destroy int pthread_mutex_destroy(pthread_mutex_t *mutex); • Attributes • Protocol, sharing, … int pthread_mutexattr_init(pthread_mutexattr_t *attr); int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); int pthread_mutexattr_getXXX(const pthread_mutexattr_t *attr, TTT *av); int pthread_mutexattr_setXXX(pthread_mutexattr_t *attr, TTT av);
Mutexes – locking • Blocking lock int pthread_mutex_lock(pthread_mutex_t *mutex); • Non-blocking lock int pthread_mutex_trylock(pthread_mutex_t *mutex); • Unlock int pthread_mutex_unlock(pthread_mutex_t *mutex);
Condition variables • Create int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); • Destroy int pthread_cond_destroy(pthread_cond_t *cond); • Attributes • Clock, sharing, … int pthread_condattr_destroy(pthread_condattr_t *attr); int pthread_condattr_init(pthread_condattr_t *attr); int pthread_condattr_getXXX(const pthread_condattr_t *attr, TTT *av); int pthread_condattr_setXXX(pthread_condattr_t *attr, TTT av);
Condition variables – locking • Blocking wait int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); • Blocking timed wait int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); • Unblock one int pthread_cond_signal(pthread_cond_t *cond); • Unblock all int pthread_cond_broadcast(pthread_cond_t *cond);
R/W lock • Create intpthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); • Destroy intpthread_rwlock_destroy(pthread_rwlock_t *rwlock); • Attributes • Sharing, … intpthread_rwlockattr_destroy(pthread_rwlockattr_t *attr); intpthread_rwlockattr_init(pthread_rwlockattr_t *attr); intpthread_rwlockattr_getXXX(constpthread_rwlockattr_t *attr, TTT *av); intpthread_rwlockattr_setXXX(pthread_rwlockattr_t *attr, TTT av);
R/W lock – reader • Blocking lock int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); • Non-blocking lock int thread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); • Timed lock int thread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, const struct timespec *abs_timeout); • Unlock int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
R/W lock – writer • Blocking lock int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); • Non-blocking lock int thread_rwlock_trywrlock(pthread_rwlock_t *rwlock); • Timed lock int thread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *abs_timeout); • Unlock int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
Barrier • Init intpthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned count); • Destroy intpthread_barrier_destroy(pthread_barrier_t *barrier); • Wait intpthread_barrier_wait(pthread_barrier_t *barrier); • Attributes • Sharing, … intpthread_barrierattr_destroy(pthread_barrierattr_t *attr); intpthread_barrierattr_init(pthread_barrierattr_t *attr); intpthread_barrierattr_getXXX(constpthread_barrierattr_t *attr, TTT *av); intpthread_barrierattr_setXXX(pthread_barrierattr_t *attr, TTT av);
Spin-lock • Create int pthread_spin_init(pthread_spinlock_t *lock, int pshared); • Destroy int pthread_spin_destroy(pthread_spinlock_t *lock); • Wait int pthread_spin_lock(pthread_spinlock_t *lock); • Non-blocking wait int pthread_spin_trylock(pthread_spinlock_t *lock); • Unblock int pthread_spin_unlock(pthread_spinlock_t *lock);
Thread local storage • Create • dest_routine called at thread exit int pthread_key_create(pthread_key_t * key, void (* dest_routine(void *))); • Destroy int pthread_key_delete(pthread_key_t key); • Set int pthread_setspecific(pthread_key_t key, const void * pointer); • Get void * pthread_getspecific(pthread_key_t key);
ISO C++ 2011 overview • Threads • Mutexes • Condition variables • Atomic variables • Futures • A future is a token for a value that will be available later • Focus on communication between threads • Synchronization details left to library
Futures • std::future • Defines a type for asynchronous return object which do not share their shared state • std::shared_future • Like future but may share their shared state • std::promise • Explicitly set shared state • std::packaged_task • Shared state is the result of a function call • std::async • Launching a function potentially in a new thread
Futures – example double comp(vector<double>& v) { // package the tasks: // (the task here is the standard accumulate() for an array of doubles): packaged_task<double(double*,double*,double)> pt0{std::accumulate<double*,double*,double>}; packaged_task<double(double*,double*,double)> pt1{std::accumulate<double*,double*,double>}; auto f0 = pt0.get_future(); // get hold of the futures auto f1 = pt1.get_future(); pt0(&v[0],&v[v.size()/2],0); // start the threads pt1(&[v.size()/2],&v[size()],0); return f0.get()+f1.get(); // get the results }
Futures – async example template<class T, class V> structAccum { // simpleaccumulatorfunctionobject T* b;T* e;V val; Accum(T* bb, T* ee, const V& v):b{bb},e{ee},val{vv} {} V operator() () { returnstd::accumulate(b,e,val); } }; double comp(vector<double>& v){ // spawn many tasksif v islargeenough if (v.size()<10000) returnstd::accumulate(v.begin(),v.end(),0.0); auto f0 {async(Accum{&v[0],&v[v.size()/4],0.0})}; auto f1 {async(Accum{&v[v.size()/4],&v[v.size()/2],0.0})}; auto f2 {async(Accum{&v[v.size()/2],&v[v.size()*3/4],0.0})}; auto f3 {async(Accum{&v[v.size()*3/4],&v[v.size()],0.0})}; return f0.get()+f1.get()+f2.get()+f3.get(); }
Threads • Simple low-level access • std::thread • Namespace this_thread • thread::id get_id() • void yield() • void sleep_until(abs_time) • void sleep_for(rel_time) • bool joinable() const • void join() • void detach()
Threads – example void f(); struct F { void operator()(); }; int main() { std::thread t1{f}; // f() executes in separate thread std::thread t2{F()}; // F()() executes in separate thread t1.join(); // wait for t1 t2.join(); // wait for t2 }
Mutexes • Classes • std::mutex • std::recursive_mutex • std::timed_mutex • std::recursive_timed_mutex • Operations • void m.lock() • boolm.try_lock() • void m.unlock() • Timed mutexes operations • booltm.try_lock_for(rel_time) • booltm.try_lock_until(abs_time)
Condition variables • Class std::condition_variable • void notify_one() • void notify_all() • void wait() • bool wait_for(rel_time) • bool wait_until(abs_time) • Class std::condition_variable_any • Use any mutex
Locks • Class std::lock_guard • Scope lock • Class std::unique_lock • Controls ownership • Generic lock template <class L1, class L2, class... L3> void lock(L1&, L2&, L3&...); • Call once classinformation { std::once_flag verified; voidverifier(); public: voidverify() { std::call_once(verified,verifier); } };
Atomic variables • Generic template atomic • compare_exchange • load, store • Specialization for basic types • fetch_add, fetch_sub, fetch_and, fetch_or, fetch_xor • Class atomic_flag • bool test_and_test() • Fences