zoukankan      html  css  js  c++  java
  • 线程池初探(NTPL/pthread)

      最近计网课设选择了写一个ftp服务器,其中我想把服务器端写成多线程部分。由此接触了posix线程及其相关部分。相关阅读书籍:【1】现代操作系统 【2】posix多线程程序设计。

      关于第二本是02年的,很久没出过新版了,NTPL与17年前的接口仍然大多一致,甚至是一样,由此引发了一些思考:现在那些花里胡哨的技术更新太快了,比如说java,c#,甚至c++每隔两年就要发布一个新的标准,然而这些底层接口仍然不变,学好了这些基础是不是更棒呢。

      步入正题:我最初想的线程池是弹出式的:也就是有一个请求到来,进程就为该请求创建一个线程。代码如下:

    class sample
    {
    public:
        void process();
    };
    
    template <typename T>
    class threadPool
    {
    public:
        threadPool();
        void append(T &s);
        static void *worker(void *s);
        ~threadPool()
        {
            if(ifDestroy==false)
            {
                destroy();
            }
        }
    
        void destroy()
        {
            pthread_mutex_destroy(&t);
            destroy=true;
        }
    
    private:
        pthread_t threads[3];
        bool run = true;
        bool ifDestroy=false;
    };
    
    template <typename T>
    void threadPool<T>::append(T& s)
    {
        pthread_t t;
        pthread_create(&t,nullptr,worker,&s);
        pthread_detach(t);
     }
    
    template <typename T>
    threadPool<T>::threadPool()
    {

    } template <typename T> void *threadPool<T>::worker(void *s) { auto work= static_cast<sample *>(s); work->process(); return nullptr; } #endif //!THREAD_POOL_H

      这里我把请求的地址作为参数传入线程,并将之设置为分离的(detached)。

      关于线程的start_routine成员函数必须是静态的,这个还不清楚为什么,难道是跟c++的多态特性不兼容吗?

      这个的缺点是显而易见的:若任务很小,只需要不多的指令,那么频繁的创建和回收销毁线程的开销则是巨大的。由此引入了我的线程池的下一个版本:

      

      这回使用了mutex(mutual exclusion)互斥锁

    class sample
    {
    public:
        void process();
    };
    
    template <typename T>
    class threadPool
    {
    public:
        threadPool();
        void append(T &s);
        static void *worker(void *s);
        ~threadPool()
        {
            if(ifDestroy==false)
            {
                destroy();
            }
        }
    
        void destroy()
        {
            pthread_mutex_destroy(&t);
            destroy=true;
        }
    
    private:
        std::queue<T *> tasks;
        pthread_t threads[3];
        bool run = true;
        pthread_mutex_t t;
        bool ifDestroy=false;
    };
    
    // template <typename T>
    // void threadPool<T>::append(T& s)
    // {
    //     pthread_t t;
    //     pthread_create(&t,nullptr,worker,&s);
    //     pthread_detach(t);
    // }
    template <typename T>
    threadPool<T>::threadPool() : tasks()
    {
        pthread_mutex_init(&t, nullptr);
        for (int i = 0; i < 3; ++i)
        {
            pthread_create(&threads[i], nullptr, worker, this);
            pthread_detach(threads[i]);
        }
    }
    
    template <typename T>
    void threadPool<T>::append(T &s)
    {
        pthread_mutex_lock(&t);
        tasks.push(static_cast<T *>(&s));
        printf("%u append.
    ", pthread_self());
        pthread_mutex_unlock(&t);
    }
    
    template <typename T>
    void *threadPool<T>::worker(void *s)
    {
        auto pool = static_cast<threadPool<T> *>(s);
        while (pool->run)
        {
            pthread_mutex_lock(&(pool->t));
            if(pool->tasks.empty())
            {
                pthread_mutex_unlock(&(pool->t));
           pthread_yeild();
    continue; } T *work = pool->tasks.front(); pool->tasks.pop(); pthread_mutex_unlock(&(pool->t)); work->process(); } return nullptr; } #endif //!THREAD_POOL_H

      这个线程池用一个队列来先存储请求,用mutex保证其原子性(atomic),串行性。【2】的p:52说道:“互斥量的本质是在串行执行”。因为还不想涉及到条件变量和信号量,所以这里当工作线程检测到队列为空时就pthread_yield()暂时放弃cpu资源给其他线程,然而这样的不足仍有很多:比如当队列为空时,工作线程就会频繁地加锁解锁损耗计算机。【2】的p:52说到:”互斥量不是免费的。需要时间来加锁解锁。“

      

      关于信号量和条件变量,且听下回分解。

  • 相关阅读:
    【Android 应用开发】 Android 相关代码规范 更新中 ...
    【IOS 开发】Object
    【Android 应用开发】 Android APK 反编译 混淆 反编译后重编译
    【IOS 开发】Object
    Unity3D 学习教程 14 C# 旋转镜头
    Unity3D 学习教程 13 C# 销毁炮弹
    Unity3D 学习教程 12 C# 发射炮弹
    Unity3D 学习教程 11 c#脚本控制摄像头
    Unity3D 学习教程 10 复制物体
    Unity3D 学习教程 9 旋转 放大 移动 物体
  • 原文地址:https://www.cnblogs.com/manch1n/p/10859705.html
Copyright © 2011-2022 走看看