thread.cpp

来自「Boost provides free peer-reviewed portab」· C++ 代码 · 共 677 行 · 第 1/2 页

CPP
677
字号
// Copyright (C) 2001-2003// William E. Kempf// Copyright (C) 2007-8 Anthony Williams////  Distributed under the Boost Software License, Version 1.0. (See accompanying //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)#include <boost/thread/detail/config.hpp>#include <boost/thread/thread.hpp>#include <boost/thread/xtime.hpp>#include <boost/thread/condition.hpp>#include <boost/thread/locks.hpp>#include <boost/thread/once.hpp>#include <boost/thread/tss.hpp>#ifdef __linux__#include <sys/sysinfo.h>#elif defined(__APPLE__) || defined(__FreeBSD__)#include <sys/types.h>#include <sys/sysctl.h>#elif defined BOOST_HAS_UNISTD_H#include <unistd.h>#endif#include "timeconv.inl"namespace boost{    namespace detail    {        thread_data_base::~thread_data_base()        {}        struct thread_exit_callback_node        {            boost::detail::thread_exit_function_base* func;            thread_exit_callback_node* next;            thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,                                      thread_exit_callback_node* next_):                func(func_),next(next_)            {}        };        struct tss_data_node        {            void const* key;            boost::shared_ptr<boost::detail::tss_cleanup_function> func;            void* value;            tss_data_node* next;            tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,                          tss_data_node* next_):                key(key_),func(func_),value(value_),next(next_)            {}        };        namespace        {            boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;            pthread_key_t current_thread_tls_key;            extern "C"            {                void tls_destructor(void* data)                {                    boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);                    if(thread_info)                    {                        while(thread_info->tss_data || thread_info->thread_exit_callbacks)                        {                            while(thread_info->thread_exit_callbacks)                            {                                detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;                                thread_info->thread_exit_callbacks=current_node->next;                                if(current_node->func)                                {                                    (*current_node->func)();                                    delete current_node->func;                                }                                delete current_node;                            }                            while(thread_info->tss_data)                            {                                detail::tss_data_node* const current_node=thread_info->tss_data;                                thread_info->tss_data=current_node->next;                                if(current_node->func)                                {                                    (*current_node->func)(current_node->value);                                }                                delete current_node;                            }                        }                        thread_info->self.reset();                    }                }            }                void create_current_thread_tls_key()            {                BOOST_VERIFY(!pthread_key_create(&current_thread_tls_key,&tls_destructor));            }        }                boost::detail::thread_data_base* get_current_thread_data()        {            boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);            return (boost::detail::thread_data_base*)pthread_getspecific(current_thread_tls_key);        }        void set_current_thread_data(detail::thread_data_base* new_data)        {            boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);            BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));        }    }        namespace    {        extern "C"        {            void* thread_proxy(void* param)            {                boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;                thread_info->self.reset();                detail::set_current_thread_data(thread_info.get());                try                {                    thread_info->run();                }                catch(thread_interrupted const&)                {                }                catch(...)                {                    std::terminate();                }                detail::tls_destructor(thread_info.get());                detail::set_current_thread_data(0);                boost::lock_guard<boost::mutex> lock(thread_info->data_mutex);                thread_info->done=true;                thread_info->done_condition.notify_all();                return 0;            }        }        struct externally_launched_thread:            detail::thread_data_base        {            externally_launched_thread()            {                interrupt_enabled=false;            }                        void run()            {}        private:            externally_launched_thread(externally_launched_thread&);            void operator=(externally_launched_thread&);        };        detail::thread_data_base* make_external_thread_data()        {            detail::thread_data_base* const me(new externally_launched_thread());            me->self.reset(me);            set_current_thread_data(me);            return me;        }        detail::thread_data_base* get_or_make_current_thread_data()        {            detail::thread_data_base* current_thread_data(detail::get_current_thread_data());            if(!current_thread_data)            {                current_thread_data=make_external_thread_data();            }            return current_thread_data;        }    }    thread::thread()    {}    void thread::start_thread()    {        thread_info->self=thread_info;        int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get());        if (res != 0)        {            thread_info->self.reset();            throw thread_resource_error();        }    }    thread::~thread()    {        detach();    }    detail::thread_data_ptr thread::get_thread_info() const    {        lock_guard<mutex> l(thread_info_mutex);        return thread_info;    }    void thread::join()    {        detail::thread_data_ptr const local_thread_info=get_thread_info();        if(local_thread_info)        {            bool do_join=false;                        {                unique_lock<mutex> lock(local_thread_info->data_mutex);                while(!local_thread_info->done)                {                    local_thread_info->done_condition.wait(lock);                }                do_join=!local_thread_info->join_started;                                if(do_join)                {                    local_thread_info->join_started=true;                }                else                {                    while(!local_thread_info->joined)                    {                        local_thread_info->done_condition.wait(lock);                    }                }            }            if(do_join)            {                void* result=0;                BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));                lock_guard<mutex> lock(local_thread_info->data_mutex);                local_thread_info->joined=true;                local_thread_info->done_condition.notify_all();            }                        lock_guard<mutex> l1(thread_info_mutex);            if(thread_info==local_thread_info)            {                thread_info.reset();            }        }    }    bool thread::timed_join(system_time const& wait_until)    {        detail::thread_data_ptr const local_thread_info=get_thread_info();        if(local_thread_info)        {            bool do_join=false;                        {                unique_lock<mutex> lock(local_thread_info->data_mutex);                while(!local_thread_info->done)                {                    if(!local_thread_info->done_condition.timed_wait(lock,wait_until))                    {                        return false;                    }                }                do_join=!local_thread_info->join_started;                                if(do_join)                {                    local_thread_info->join_started=true;                }                else                {                    while(!local_thread_info->joined)                    {                        local_thread_info->done_condition.wait(lock);                    }                }            }            if(do_join)            {                void* result=0;                BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));                lock_guard<mutex> lock(local_thread_info->data_mutex);                local_thread_info->joined=true;                local_thread_info->done_condition.notify_all();            }                        lock_guard<mutex> l1(thread_info_mutex);            if(thread_info==local_thread_info)            {                thread_info.reset();            }        }        return true;    }    bool thread::joinable() const    {        return get_thread_info();    }    void thread::detach()    {        detail::thread_data_ptr local_thread_info;        {            lock_guard<mutex> l1(thread_info_mutex);            thread_info.swap(local_thread_info);        }                if(local_thread_info)        {            lock_guard<mutex> lock(local_thread_info->data_mutex);            if(!local_thread_info->join_started)            {                BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));                local_thread_info->join_started=true;                local_thread_info->joined=true;            }        }    }    namespace this_thread    {                void sleep(const system_time& st)        {            detail::thread_data_base* const thread_info=detail::get_current_thread_data();                    if(thread_info)            {                unique_lock<mutex> lk(thread_info->sleep_mutex);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?