您的位置:首页 > 编程语言 > C语言/C++

c++封装线程

2015-07-29 17:17 211 查看

线程

(1)Linux线程库有两个流行的线程库,分别是LinuxThreads和NPTL,由于LinuxThreads的某些缺点,已经被NPTL取代,它们都是基于1:1模式实现,即1个用户线程被映射为1个内核线程;故每一个用户线程在内核中有唯一的标识;线程标识使用pthread_t有问题!!!
void* loop(void*){cout  << "Thread run" << endl;return NULL;}int main(){pthread_t t1, t2;errno = pthread_create(&t1, NULL, loop, NULL);assert(!errno);pthread_join(t1, NULL);pthread_create(&t2, NULL, loop, NULL);assert(!errno);pthread_join(t2, NULL);cout  << hex << t1 << " " << t2 << endl;return 0;}  
说明几点:(1)验证该代码片段可得:上述t1和t2值相同;Pthreads只能保证同一进程中各线程pthread_t在同一时刻不同,不能保证同一线程具有不同的id;(2)pthread_t在某些应用场合不能作为线程的标识,比如一个线程已经死亡,而此时创建一个新的线程,可能重用了旧的pthread_t,导致本来与旧线程交互的数据,开始又和新的线程错误执行;(3)解决办法:由于NPTL基于1:1模式(1个用户线程被映射为1个内核线程)实现;故每一个用户线程在内核中也有唯一的标识,使用gettid()可以获得该标识,为了减少系统调用次数,可使用__thread进行缓存该id,这样只有第一次使用该id才会调用gettid()系统调用,但是可移植性会降低;下述代码中__thread缓存tid;syscall(SYS_gettid)为直接使用系统调用号执行系统调用,即直接获取某执行线程的唯一线程ID;实现代码如下:
namespace CurrentThread{pid_t gettid(){return syscall(SYS_gettid);}__thread pid_t t_tid;static pthread_t tid(){if (t_tid == 0){t_tid = gettid();}return t_tid;}}  

thread声明如下:
namespace CurrentThread{extern __thread pid_t t_tid;extern pid_t tid();}//notice: we should make Thread object's life longer than thread, so we shold always use fun: join,class Thread final{public:Thread(const Thread&) = delete;Thread& operator=(const Thread&) = delete;typedef std::function<void()> ThreadFunc;explicit Thread(const ThreadFunc& func);void start();bool running() const{return _running;}int join(){int err = pthread_join(_threadId, NULL);return err;}pid_t tid() const{return _tid;}private:void _runInThread();static void* _threadFunc(void*);pid_t _tid;pthread_t _threadId;ThreadFunc _func;bool _running;};  
说明几点:(1)_tid为线程的唯一标识,也就是利用上述CurrentThread和__thread来实现获得的;(2)线程与Thread对象的生命周期,要注意Thread对象析构和线程终止的顺序关系;当调用thread.join()函数时,可以保证Thread对象在线程终止之后析构;若没有调用thread.join()函数,将会出现thread先析构的情况,此时C++析构会自动deatch线程,因此保证资源不会泄漏,但是线程在使用继续使用Thread相关资源时,执行过程将会出现未定义情况;因此我们应该保证使用thread.join()函数,即Thread的生命周期要长于线程的生命周期;

thread实现如下:

__thread pid_t  CurrentThread::t_tid = 0;pid_t CurrentThread::tid(){if (t_tid == 0)t_tid = syscall(SYS_gettid);return t_tid;}Thread::Thread(const ThreadFunc& func):_func(func),_running(false){}void Thread::start(){assert(!_running);_running = true;int err = pthread_create(&_threadId, NULL, Thread::_threadFunc, this);if (err != 0){cout << "pthread_create system error";}}void Thread::_runInThread(){assert(_running);try{_tid = CurrentThread::tid();       //impotant, the time we obtain tid;cout << "Thread tid[" << _tid << "] is threadFunc";if (_func)_func();}catch (...){cout << "Exception happen in Thread";}}void* Thread::_threadFunc(void* obj)      //remember obj's scope in self class{Thread* thread = static_cast<Thread*>(obj);thread->_runInThread();return NULL;}  
说明几点:(1)static void* _threadFunc(void*)为Thread的static成员函数,而不是成员函数,因为pthread_create(&_threadId, NULL, Thread::_threadFunc, this)接收的函数类型必须是一个类似全局的函数,使用非static成员函数,显然我们还要传递相对应的对象指针,pthread_create是无法接收的;(2)在_runInThread()中,使用 catch (...)捕捉线程执行过程中的一切异常;测试代码:
#include <Base/Thread.h>#include <stdio.h>using namespace std;using namespace Base;void func1() {printf("%s %d\n", "func1: tid", CurrentThread::tid());}void func2() {printf("%s %d\n", "func2: tid", CurrentThread::tid());}int main(void) {Thread thread1(func1);Thread thread2(func2);thread1.start();thread2.start();thread1.join();thread2.join();return 0;}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线程 linux