云计算百科
云计算领域专业知识百科平台

Linux之线程池(二)

设计线程池

大纲

成员变量

成员函数

先完成一个基本框架的设计

构造

由于我们调用是说我们自己设计的thread

start wait stop

和单线程那里类似

主要是让所有线程都开启上面那些函数

测试一下

以上基本功能已经实现,接下来我们对其进行改变一下

这个任务相当于是全局的,要是我们想要让他在类里面实现该又怎么做呢??

我们将任务函数变成成员函数

编译的时候发现失败了这是为什么????

普通成员函数隐含参数this,类型是 void (ThreadPool<int>::*)(),不是普通函数指针 void (*)(),Thread 类构造只接收普通函数指针,编译直接报错。

那么应该如何解决???

首先我们可以先让他变成static

当然我们也可以用

直接用lambda 捕获 this传入,完美解决!

std::function<void()>可以接收:

  • 普通全局函数
  • lambda 表达式(可以捕获this)
  • bind 绑定成员函数
  • 上面谈完这个问题,

    接下来我们对任务进行更加细致的修改

    再执行任务的时候是要进行加锁和减锁的

    因为要求每个线程调用的任务是不重复的

    再临界区内我们哟啊检测任务,

    如果有任务该怎么办

    没有任务有该怎么办

    有任务,取任务就是将公共资源变成私有的

    enqueue

    唤醒线程的逻辑是只要有有线程处于休眠状态就进行唤醒

    测试

    对于stop逻辑的更新

    需求:

  • 使用_isrunning标志位控制线程池运行状态
  • 队列中剩余任务全部执行完毕之后,工作线程才允许退出
  • 使用Broadcast唤醒所有休眠的工作线程
  • 线程处理函数(handler)内部判断条件,自动 break 退出循环
  • 也就是说对于handler函数那里还需要做出调整

    当任务不为空的时候,要继续执行,也就是说不能让线程休眠

    当线程池要退出时,线程也不能休眠,

    任意满足上面两条都是不可以进行休眠

    —>那什么时候可以进行休眠呢??

    当上面两条都不满足的时候

    测试

    class Task
    {
    public:
    ~Task()
    {
    }
    Task(int x, int y)
    : _x(x),
    _y(y)
    {
    }
    void Excute()
    {
    _ret = _x + _y;
    }
    void operator()()
    {
    _ret = _x + _y;
    }
    string PrintAns()
    {
    return to_string(_x) + "+" + to_string(_y) + "=" + to_string(_ret);
    }
    string PrintQuestion()
    {
    return to_string(_x) + "+" + to_string(_y) + "=?";
    }

    private:
    int _x;
    int _y;
    int _ret;
    };

    using task_t = function<void()>;

    int main()
    {
    srand(time(nullptr) ^ getpid());
    ENABLE_CONSOLESTRATEGY();
    unique_ptr<ThreadPool<Task>> pool = make_unique<ThreadPool<Task>>();
    pool->Start();
    int cnt = 10;
    while (cnt–)
    {
    int x = rand() % 10 + 1;
    int y = rand() % 20 + 1;
    Task t(x, y);
    sleep(1);
    pool->Enqueue(t);
    sleep(1);
    }
    pool->Wait();

    return 0;
    }

    void handlertask()
    {
    char buf[64];
    pthread_getname_np(pthread_self(), buf, sizeof(buf));
    while (1)
    {
    // 保护临界区
    _mutex.Lock();

    // 检测任务. 不休眠->1.队列不为空2.线程池退出
    while (_qu_task.empty()&&_isrunning)
    {
    // 没有任务
    _slaver_sleep_count++;
    _cond.Wait(_mutex);
    _slaver_sleep_count–;
    }

    // 有任务或者线程池退出
    // 1&&2 —->break
    if(!_isrunning&&_qu_task.empty())
    {
    _mutex.Unlock();
    break;
    }
    // 如果模板是一个类要怎么做
    T mytask = _qu_task.front();
    _qu_task.pop();
    // 处理任务??需要在临界区内执行吗???
    // 不需要不然就成为单线程
    _mutex.Unlock();
    LOG(LogLevel::INFO) << "my name:" << buf;
    mytask();
    LOG(LogLevel::INFO) << "my job:" <<mytask.PrintAns();
    }
    }

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Linux之线程池(二)
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!