C++中std::thread线程怎么使用

发布时间:2023-01-09 09:27:57 作者:iii
来源:亿速云 阅读:178

C++中std::thread线程怎么使用

在现代C++编程中,多线程编程是一个非常重要的主题。随着硬件的发展,多核处理器已经成为主流,利用多线程可以显著提高程序的性能。C++11引入了std::thread类,使得在C++中进行多线程编程变得更加简单和直观。本文将详细介绍std::thread的使用方法,包括线程的创建、管理、同步以及一些常见的多线程编程技巧。

1. std::thread的基本用法

1.1 创建线程

在C++中,使用std::thread类可以创建一个新的线程。std::thread的构造函数接受一个可调用对象(如函数、lambda表达式、函数对象等)作为参数,并在新线程中执行该可调用对象。

#include <iostream>
#include <thread>

void hello() {
    std::cout << "Hello, World!" << std::endl;
}

int main() {
    std::thread t(hello);  // 创建一个新线程,执行hello函数
    t.join();              // 等待线程结束
    return 0;
}

在上面的例子中,std::thread t(hello)创建了一个新线程,并在该线程中执行hello函数。t.join()用于等待线程结束。

1.2 传递参数给线程函数

std::thread的构造函数还可以接受额外的参数,这些参数会被传递给线程函数。

#include <iostream>
#include <thread>

void print_message(const std::string& message) {
    std::cout << message << std::endl;
}

int main() {
    std::thread t(print_message, "Hello from thread!");
    t.join();
    return 0;
}

在这个例子中,print_message函数接受一个std::string类型的参数。std::thread的构造函数将字符串"Hello from thread!"传递给print_message函数。

1.3 使用lambda表达式

除了函数,std::thread还可以接受lambda表达式作为参数。

#include <iostream>
#include <thread>

int main() {
    std::thread t([]() {
        std::cout << "Hello from lambda!" << std::endl;
    });
    t.join();
    return 0;
}

在这个例子中,std::thread的构造函数接受一个lambda表达式,该表达式在新线程中执行。

1.4 线程的分离

std::thread对象可以通过detach()方法将线程与std::thread对象分离。分离后的线程将在后台运行,不再与std::thread对象关联。

#include <iostream>
#include <thread>

void background_task() {
    std::cout << "Background task is running..." << std::endl;
}

int main() {
    std::thread t(background_task);
    t.detach();  // 分离线程
    std::cout << "Main thread continues..." << std::endl;
    return 0;
}

在这个例子中,t.detach()将线程与std::thread对象分离,主线程继续执行,而background_task在后台运行。

1.5 线程的移动

std::thread对象是不可复制的,但可以移动。这意味着你可以将一个std::thread对象的所有权转移给另一个std::thread对象。

#include <iostream>
#include <thread>

void task() {
    std::cout << "Task is running..." << std::endl;
}

int main() {
    std::thread t1(task);
    std::thread t2 = std::move(t1);  // 将t1的所有权转移给t2
    t2.join();
    return 0;
}

在这个例子中,t1的所有权被转移给t2t1不再拥有线程。

2. 线程的同步

在多线程编程中,线程之间的同步是一个重要的问题。C++提供了多种同步机制,如互斥量(std::mutex)、条件变量(std::condition_variable)等。

2.1 互斥量

互斥量用于保护共享资源,防止多个线程同时访问共享资源导致数据竞争。

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>

std::mutex mtx;
int shared_data = 0;

void increment() {
    for (int i = 0; i < 100000; ++i) {
        std::lock_guard<std::mutex> lock(mtx);
        ++shared_data;
    }
}

int main() {
    std::vector<std::thread> threads;
    for (int i = 0; i < 10; ++i) {
        threads.emplace_back(increment);
    }
    for (auto& t : threads) {
        t.join();
    }
    std::cout << "Shared data: " << shared_data << std::endl;
    return 0;
}

在这个例子中,std::mutex用于保护shared_datastd::lock_guard用于自动管理互斥量的锁定和解锁。

2.2 条件变量

条件变量用于线程之间的通信,允许一个线程等待另一个线程完成某个条件。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

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

void wait_for_ready() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []() { return ready; });
    std::cout << "Ready!" << std::endl;
}

void set_ready() {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;
    }
    cv.notify_all();
}

int main() {
    std::thread t1(wait_for_ready);
    std::thread t2(set_ready);
    t1.join();
    t2.join();
    return 0;
}

在这个例子中,wait_for_ready线程等待set_ready线程将ready设置为truecv.wait会阻塞线程,直到readytrue

2.3 原子操作

C++11引入了std::atomic,用于实现无锁的原子操作。

#include <iostream>
#include <thread>
#include <atomic>
#include <vector>

std::atomic<int> shared_data(0);

void increment() {
    for (int i = 0; i < 100000; ++i) {
        ++shared_data;
    }
}

int main() {
    std::vector<std::thread> threads;
    for (int i = 0; i < 10; ++i) {
        threads.emplace_back(increment);
    }
    for (auto& t : threads) {
        t.join();
    }
    std::cout << "Shared data: " << shared_data << std::endl;
    return 0;
}

在这个例子中,std::atomic<int>用于保护shared_data,避免了使用互斥量的开销。

3. 线程的管理

3.1 线程的ID

每个线程都有一个唯一的ID,可以通过std::thread::get_id()获取。

#include <iostream>
#include <thread>

void task() {
    std::cout << "Thread ID: " << std::this_thread::get_id() << std::endl;
}

int main() {
    std::thread t1(task);
    std::thread t2(task);
    t1.join();
    t2.join();
    return 0;
}

在这个例子中,std::this_thread::get_id()用于获取当前线程的ID。

3.2 线程的数量

可以通过std::thread::hardware_concurrency()获取系统支持的并发线程数。

#include <iostream>
#include <thread>

int main() {
    unsigned int n = std::thread::hardware_concurrency();
    std::cout << "Number of concurrent threads supported: " << n << std::endl;
    return 0;
}

3.3 线程的优先级

C++标准库没有直接提供设置线程优先级的方法,但可以通过平台特定的API来实现。

#include <iostream>
#include <thread>
#include <pthread.h>

void task() {
    std::cout << "Task is running..." << std::endl;
}

int main() {
    std::thread t(task);
    pthread_t native_handle = t.native_handle();
    pthread_setschedprio(native_handle, 10);  // 设置线程优先级
    t.join();
    return 0;
}

在这个例子中,pthread_setschedprio用于设置线程的优先级。

4. 线程池

在实际应用中,频繁地创建和销毁线程会带来较大的开销。线程池是一种常见的解决方案,它预先创建一组线程,并在需要时分配任务给这些线程。

C++标准库没有直接提供线程池的实现,但可以通过std::threadstd::queue等工具来实现一个简单的线程池。

#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <functional>
#include <mutex>
#include <condition_variable>

class ThreadPool {
public:
    ThreadPool(size_t num_threads) {
        for (size_t i = 0; i < num_threads; ++i) {
            workers.emplace_back([this] {
                while (true) {
                    std::function<void()> task;
                    {
                        std::unique_lock<std::mutex> lock(this->queue_mutex);
                        this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
                        if (this->stop && this->tasks.empty()) {
                            return;
                        }
                        task = std::move(this->tasks.front());
                        this->tasks.pop();
                    }
                    task();
                }
            });
        }
    }

    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            stop = true;
        }
        condition.notify_all();
        for (std::thread& worker : workers) {
            worker.join();
        }
    }

    template <class F>
    void enqueue(F&& f) {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            tasks.emplace(std::forward<F>(f));
        }
        condition.notify_one();
    }

private:
    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;
    std::mutex queue_mutex;
    std::condition_variable condition;
    bool stop = false;
};

int main() {
    ThreadPool pool(4);
    for (int i = 0; i < 8; ++i) {
        pool.enqueue([i] {
            std::cout << "Task " << i << " is running on thread " << std::this_thread::get_id() << std::endl;
        });
    }
    return 0;
}

在这个例子中,ThreadPool类实现了一个简单的线程池。线程池预先创建了一组线程,并通过任务队列分配任务给这些线程。

5. 总结

std::thread是C++11引入的一个强大的工具,使得多线程编程变得更加简单和直观。通过std::thread,我们可以轻松地创建和管理线程,并通过互斥量、条件变量等同步机制来保证线程安全。此外,线程池等高级技术可以进一步提高多线程程序的性能和可维护性。

在实际开发中,多线程编程需要谨慎处理,避免数据竞争、死锁等问题。通过合理地使用std::thread及其相关工具,我们可以编写出高效、可靠的多线程程序。

推荐阅读:
  1. 游戏开发有哪些常用的软件
  2. C++20协程的使用方法

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c++ std::thread

上一篇:IDEA Debug问题怎么解决

下一篇:SpringBoot如何实现设置全局和局部时间格式化

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》