我是线程[1]操作详解

一、线程的定义

线程是计算机中最小的可执行单元,是操作系统中进行CPU调度和分配的基本单位,一个进程可以包含多个线程。不同于进程间的资源隔离,不同线程之间可以共享进程的资源,如内存、文件描述符等。线程主要包括线程标识符、程序计数器、寄存器集合、栈和线程本地存储区域等组成部分。

二、线程的创建和销毁

在C++11标准中,线程的创建和销毁主要由std::thread类来实现,创建线程的基本形式如下:

#include <thread>
void function_to_execute();
std::thread t(function_to_execute); //创建一个新线程

创建新线程时需要指定线程需要执行的函数名或lambda表达式,在这里function_to_execute()为线程函数,std::thread t是线程对象。销毁线程主要有detach()函数和join()函数,前者将线程与线程对象解绑,允许线程对象独立运行,后者等待线程执行完成后才继续执行主线程。

三、线程的同步

多个线程之间进行资源共享时,需要注意同步问题。引入同步机制可以防止多个线程同时对同一个资源进行访问并产生冲突,通常采用互斥量和条件变量实现同步。在C++11标准中,互斥量(std::mutex)用于保护共享数据资源,条件变量(std::condition_variable)提供了一种等待通知的机制。

#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void function1() {
    std::unique_lock<std::mutex> lck(mtx);
    // 同步执行
    cv.wait(lck, []{return ready;});
    // 继续执行
}

void function2() {
    // 准备数据
    {
        std::lock_guard<std::mutex> lck(mtx);
        // 获得锁
        ready = true;
    }
    cv.notify_one();
    // 通知另一个线程
}

上面代码中,mutex被用来保护一个boolean类型的ready变量。function1()和function2()都需要使用控制ready变量的线程同步机制来确保ready已经被设置。function1()上锁,调用wait()函数开始等待,直到另一个线程上锁并调用notify_one()函数来解除等待并继续执行。function2()设置ready后,调用notify_one()函数向另一个线程通知数据已准备好。

四、线程的安全性问题

在多线程编程中,可能出现数据竞争、死锁、饥饿、优先级反转等问题。其中数据竞争是典型的线程不安全问题,通常通过使用原子类型、锁等手段来解决。原子类型是一种特殊类型,可以保证对其操作的“原子性”,即线程安全。std::atomic类提供了常用的原子类型,如std::atomic_int、std::atomic_bool等。

#include <atomic>
std::atomic_int a(0);
void increase() { a++; }

上面代码中,std::atomic_int类的对象a可以通过该类提供的++操作进行原子递增,从而保证多个线程之间的线程安全。

五、线程的优化

优化多线程程序的性能是程序员们需要面对的挑战之一。线程池是一个常用的优化多线程程序的手段。线程池的本质是维护一定数量的线程,用于执行需要并发处理的任务,线程池可以避免反复创建和销毁线程的开销,降低了线程创建带来的性能影响。

#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <queue>

std::queue<std::function<void()>> taskQueue;
std::mutex taskMutex;
std::condition_variable taskCV;
std::atomic_bool stop_flag(false);

void worker() {
    std::function<void()> task;
    while (true) {
        {
            std::unique_lock<std::mutex> lock(taskMutex);
            taskCV.wait(lock, []{ return !taskQueue.empty() || stop_flag.load(); });
            if (stop_flag && taskQueue.empty()) {
                return;
            } else if (!taskQueue.empty()) {
                task = taskQueue.front();
                taskQueue.pop();
            } else {
                continue;
            }
        }
        task();
    }
}

class ThreadPool {
public:
    ThreadPool(size_t numThreads) {
        for (size_t i = 0; i < numThreads; i++) {
            workers.emplace_back(worker);
        }
    }

    ~ThreadPool() {
        stop_flag = true;
        taskCV.notify_all();
        for (auto& worker : workers) {
            worker.join();
        }
    }

    template <typename F, typename ...Args>
    auto addTask(F&& f, Args&& ...args) {
        auto task = std::make_shared<std::function<void()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
        std::unique_lock<std::mutex> lock(taskMutex);
        taskQueue.emplace([task](){ (*task)(); });
        taskCV.notify_one();
        return task;
    }

private:
    std::vector<std::thread> workers;
};

ThreadPool pool(4);

void thread_func(int x, int y) {
    for (int i = x; i < y; i++) {
        printf("thread id: %d\n", std::this_thread::get_id());
        printf("i = %d\n", i);
    }
}

void test_thread_pool() {
    for (int i = 0; i < 10; i++) {
        auto task = pool.addTask(thread_func, i * 10, i * 10 + 10);
    }
}

上述代码实现了一个简单的线程池,包括添加任务、等待任务、执行任务等基本功能。代码通过std::thread和std::mutex等C++标准库提供的线程相关的类和函数实现。

原创文章,作者:HWOCS,如若转载,请注明出处:https://www.506064.com/n/370022.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
HWOCSHWOCS
上一篇 2025-04-18 13:40
下一篇 2025-04-18 13:40

相关推荐

  • Python栈操作用法介绍

    如果你是一位Python开发工程师,那么你必须掌握Python中的栈操作。在Python中,栈是一个容器,提供后进先出(LIFO)的原则。这篇文章将通过多个方面详细地阐述Pytho…

    编程 2025-04-29
  • Python操作数组

    本文将从多个方面详细介绍如何使用Python操作5个数组成的列表。 一、数组的定义 数组是一种用于存储相同类型数据的数据结构。Python中的数组是通过列表来实现的,列表中可以存放…

    编程 2025-04-29
  • Python操作MySQL

    本文将从以下几个方面对Python操作MySQL进行详细阐述: 一、连接MySQL数据库 在使用Python操作MySQL之前,我们需要先连接MySQL数据库。在Python中,我…

    编程 2025-04-29
  • Python磁盘操作全方位解析

    本篇文章将从多个方面对Python磁盘操作进行详细阐述,包括文件读写、文件夹创建、删除、文件搜索与遍历、文件重命名、移动、复制、文件权限修改等常用操作。 一、文件读写操作 文件读写…

    编程 2025-04-29
  • Python代码实现回文数最少操作次数

    本文将介绍如何使用Python解决一道经典的回文数问题:给定一个数n,按照一定规则对它进行若干次操作,使得n成为回文数,求最少的操作次数。 一、问题分析 首先,我们需要了解回文数的…

    编程 2025-04-29
  • Python线程等待指南

    本文将从多个方面详细讲解Python线程等待的相关知识。 一、等待线程结束 在多线程编程中,经常需要等待线程执行完毕再进行下一步操作。可以使用join()方法实现等待线程执行完毕再…

    编程 2025-04-29
  • Python元祖操作用法介绍

    本文将从多个方面对Python元祖的操作进行详细阐述。包括:元祖定义及初始化、元祖遍历、元祖切片、元祖合并及比较、元祖解包等内容。 一、元祖定义及初始化 元祖在Python中属于序…

    编程 2025-04-29
  • 如何用Python对数据进行离散化操作

    数据离散化是指将连续的数据转化为离散的数据,一般是用于数据挖掘和数据分析中,可以帮助我们更好的理解数据,从而更好地进行决策和分析。Python作为一种高效的编程语言,在数据处理和分…

    编程 2025-04-29
  • Python列表的读写操作

    本文将针对Python列表的读取与写入操作进行详细的阐述,包括列表的基本操作、列表的增删改查、列表切片、列表排序、列表反转、列表拼接、列表复制等操作。 一、列表的基本操作 列表是P…

    编程 2025-04-29
  • Python序列的常用操作

    Python序列是程序中的重要工具,在数据分析、机器学习、图像处理等很多领域都有广泛的应用。Python序列分为三种:列表(list)、元组(tuple)和字符串(string)。…

    编程 2025-04-28

发表回复

登录后才能评论