C++ 简单的任务队列详解

C++ 简单的任务队列详解

本文介绍了在 C++ 中实现一个简单的任务队列,用来处理异步任务。任务队列常用于多线程编程中,能够提高程序的并发性能。在本文中,我们将详细介绍任务队列的实现思路和步骤。

实现思路

任务队列是一个先进先出(FIFO)的数据结构,通常实现方式是使用队列。任务队列中存储的是待执行的任务。每当一个任务完成后,就从队列中取出下一个任务执行。实现一个简单的任务队列需要以下的步骤:

  1. 定义任务结构体(Task)
  2. 定义任务队列结构体(TaskQueue)
  3. 实现向任务队列中添加任务的函数(AddTask)
  4. 实现从任务队列中取出任务的函数(GetTask)

结构体定义

任务结构体(Task)应该包含以下的信息:

struct Task {
    std::function<void()> func; // 任务执行函数
    bool done; // 任务是否完成
    std::condition_variable cv; // 定义条件变量通知任务是否完成
    std::mutex lock; // 定义互斥锁
};

任务队列结构体(TaskQueue)应该包含以下的信息:

struct TaskQueue {
    std::queue<std::shared_ptr<Task>> tasks; // 存储任务的队列
    std::mutex lock; // 定义互斥锁
    std::condition_variable cv; // 定义条件变量通知有任务可执行
};

添加任务

向任务队列中添加一个任务(AddTask)时,应该将任务封装成一个 std::shared_ptr<Task> 对象,并将该对象加入到任务队列中。

void AddTask(TaskQueue& taskQueue, std::function<void()> taskFunc) {
    std::shared_ptr<Task> task = std::make_shared<Task>();
    task->func = taskFunc;
    task->done = false;
    {
        std::lock_guard<std::mutex> lock(taskQueue.lock);
        taskQueue.tasks.push(task);
    }
    taskQueue.cv.notify_one();
}

在该函数中,先创建一个 std::shared_ptr 对象,然后将任务函数和完成标记赋值给该对象的成员。接着使用锁保护任务队列,将该任务加入到队列中。最后通知所有等待该条件变量的线程有任务可执行。需要注意的是,在添加任务后需要释放锁,否则等待该条件变量的线程将不能获取到锁,无法执行下去。

取出任务

从任务队列中取出一个任务(GetTask)时,应该先检查是否有任务,若有,则返回队头的任务,否则等待条件变量。

std::shared_ptr<Task> GetTask(TaskQueue& taskQueue) {
    std::unique_lock<std::mutex> lock(taskQueue.lock);
    taskQueue.cv.wait(lock, [&]() { return !taskQueue.tasks.empty(); });
    std::shared_ptr<Task> task = taskQueue.tasks.front();
    taskQueue.tasks.pop();
    return task;
}

在该函数中,首先使用 std::unique_lock 对互斥锁进行加锁,并等待条件变量。等待条件变量的函数需要传入互斥锁和一个 lambda 表达式,返回类型为 bool。该 lambda 表达式返回 true时,等待将被唤醒。在该 lambda 表达式中,我们检查队列是否为空,若不为空则返回 true。若为空则等待条件变量唤醒。当条件变量被唤醒后,任务队列中必定有任务,从队列中取出队头的任务并返回。

示例说明

以下是两个简单的示例说明,用于说明任务队列的使用方法。

示例1

#include <iostream>
#include <thread>

#include "task_queue.h"

TaskQueue g_taskQueue;
bool g_done;

void taskThread() {
    while (!g_done) {
        std::shared_ptr<Task> currTask = GetTask(g_taskQueue);
        currTask->func();
        currTask->done = true;
        currTask->cv.notify_all();
    }
}

void printHello() {
    std::cout << "Hello" << std::endl;
}

void printWorld() {
    std::cout << "World" << std::endl;
}

int main() {
    g_done = false;
    std::thread t(taskThread);

    AddTask(g_taskQueue, printHello);
    AddTask(g_taskQueue, printWorld);

    while (true) {
        std::shared_ptr<Task> currTask = GetTask(g_taskQueue);
        if (currTask->done) {
            break;
        }
        currTask->func();
        currTask->cv.notify_all();
    }

    g_done = true;
    t.join();
    return 0;
}

在该示例中,我们创建了一个任务队列,并向队列中添加两个简单的任务函数 printHelloprintWorld。接着我们启动一个线程不断取出队列中的任务并执行。在主线程中,我们从任务队列中取出任务并执行。

示例2

#include <iostream>
#include <thread>

#include "task_queue.h"

TaskQueue g_taskQueue;
bool g_done;

void taskThread() {
    while (!g_done) {
        std::shared_ptr<Task> currTask = GetTask(g_taskQueue);
        currTask->func();
        currTask->done = true;
        currTask->cv.notify_all();
    }
}

void printHello() {
    std::cout << "Hello" << std::endl;
}

void printWorld() {
    std::cout << "World" << std::endl;
}

int main() {
    g_done = false;
    std::thread t(taskThread);

    for (int i = 0; i < 10; i++) {
        AddTask(g_taskQueue, printHello);
        AddTask(g_taskQueue, printWorld);
    }

    while (true) {
        std::shared_ptr<Task> currTask = GetTask(g_taskQueue);
        if (currTask->done) {
            break;
        }
        currTask->func();
        currTask->cv.notify_all();
    }

    g_done = true;
    t.join();
    return 0;
}

在该示例中,我们创建了一个任务队列,并向队列中添加十个简单的任务函数 printHelloprintWorld。接着我们启动一个线程不断取出队列中的任务并执行。在主线程中,我们从任务队列中取出任务并执行,待所有任务执行完毕后程序结束。

总结

任务队列作为多线程编程的重要组成部分,能够提高程序的并发性能,同时降低代码的复杂度。本文以 C++ 语言为例,介绍了一个简单而又完整的任务队列实现。我们相信这篇文章对于那些初学多线程编程的开发者们会有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++ 简单的任务队列详解 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • C语言模拟实现库函数详解

    C语言模拟实现库函数详解 1. 什么是库函数? 库函数(也称为系统函数)是一组能够被程序员调用的函数库,它包含了许多常用的功能函数。C语言本身只提供了一些基本的语法和数据类型,必须通过调用库函数来进行更高级的操作,如打印信息、内存操作、文件操作等等。 2. C语言模拟实现库函数好处 通过自己实现库函数,可以更深入地了解函数的实现原理,加深对C语言的理解。同时…

    C 2023年5月23日
    00
  • C程序 选择排序

    C程序 – 选择排序攻略 什么是选择排序? 选择排序是一种简单的排序算法。它的基本思想是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放到序列的起始位置,直到全部待排序的数据元素排完为止。 选择排序的过程 选择排序的过程可以通过以下步骤来描述: 从序列中选择最小/最大之一的元素; 把它与待排序的数组中的第一个元素交换位置; 从剩余的元素中继续选择…

    C 2023年5月9日
    00
  • C#多线程异步执行和跨线程访问控件Helper

    关于C#多线程异步执行和跨线程访问控件Helper,我会分为以下几个部分进行讲解: 什么是多线程异步执行和跨线程访问控件 为什么需要多线程异步执行和跨线程访问控件 实现多线程异步执行和跨线程访问控件的方法 示例说明:多线程异步执行 示例说明:跨线程访问控件Helper 什么是多线程异步执行和跨线程访问控件 多线程异步执行是指在执行过程中,可以有多个线程同时进…

    C 2023年5月22日
    00
  • 比特币原理是什么?比特币原理详解

    比特币原理是什么? 比特币(Bitcoin)是一种去中心化的数字货币,是基于点对点网络技术和密码学算法实现的。它的核心原领是区块链技术,是一种分布式账本技术,使得比特币能够实现去中心化、防篡改。 比特币采用共识机制来保证交易的安全和可靠性。它没有中心化的发行机构,每一笔交易都被记录到区块链上。同时,比特币的发行数量是有限的,最大发行量不超过2100万枚。 比…

    C 2023年5月22日
    00
  • 推荐几款实用的C++ 在线工具

    以下是推荐几款实用的C++ 在线工具的攻略: 推荐几款实用的C++ 在线工具 1. Codepad Codepad 是一个在线代码编辑器,它支持多种编程语言,包括 C++。Codepad 的界面简洁明了,编辑区域清晰易懂,输出结果也能够很好地呈现。使用 Codepad,你可以快速试错,调试你的 C++ 代码。 Codepad 提供的编译器版本较新,比如它使用…

    C 2023年5月23日
    00
  • Go 语言 json解析框架与 gjson 详解

    Go 语言 json解析框架与 gjson 详解 介绍 在 Golang 中,解析 JSON 数据是一项非常常见的任务。Go提供了标准的JSON包,可以轻松地将JSON数据编组和解组。但是,在使用标准JSON包解析大型复杂JSON结构时,可能存在些许不足,例如代码冗余,性能瓶颈等问题。针对这些问题,目前有许多优秀的JSON解析框架,GJSON是其中一个很不错…

    C 2023年5月23日
    00
  • win10系统更新提示错误代码0xc0000409怎么办?

    解决win10系统更新提示错误代码0xc0000409的完整攻略 问题描述 当你在win10系统中尝试进行系统更新时,突然出现错误提示:“更新时发生意外错误,错误代码0xc0000409”。这个错误代码可能让你不知所措,但是不要担心!本文将会为你提供解决方案。 解决方案 1. 确认错误信息 首先,我们需要进一步了解出现这个错误的具体原因。我们需要打开Wind…

    C 2023年5月23日
    00
  • C语言实现堆的简单操作的示例代码

    C语言实现堆的简单操作的示例代码 堆的定义 堆是指通过比较之后使得数组满足大/小根堆性质的一种近似完全二叉树结构。 堆的结构 堆有两种类型,分别为大根堆和小根堆。大根堆指所有父结点都大于等于其子结点,小根堆则相反,所有父结点都小于等于其子结点。 假设i为当前结点,那么其父结点为(i-1)/2,左子结点为(2i+1),右子结点为(2i+2)。 堆支持如下操作:…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部