C++11 之前,在 C++ 中进行多线程编程通常需要依赖平台特定的库,如 Windows 下的 Windows API,Linux 下的线程库(pthread)。不同平台的接口差异很大,代码移植性差。C++11 引入了 <thread> 等相关头文件组成的线程库

线程的创建与启动

通过std::thread类来创建和管理线程。std::thread 的构造函数接受一个可调用对象(函数、函数对象、lambda 表达式等)作为参数,线程启动后会执行这个可调用对象。

基本用法
#include <iostream>
#include <thread>

// 1. 普通函数作为线程函数
void test() {
    std::cout << "test -> thread ID: "
        << std::this_thread::get_id() << std::endl;
}

// 2. 仿函数作为线程函数
class functor {
public:
    void operator()() {
        std::cout << "functor -> thread ID: "
            << std::this_thread::get_id() << std::endl;
    }
};

// 3.  Lambda 表达式作为线程函数
auto Lambda = []() {
    std::cout << "lambda -> thread ID: "
        << std::this_thread::get_id() << std::endl;
    };

int main() {
    std::cout << "main thread ID: " << std::this_thread::get_id() << std::endl;

    // 创建线程的多种方式
    std::thread t1(test);      // 函数指针
    std::thread t2{functor()};     // 仿函数
    std::thread t3(Lambda);        // lambda
    std::thread t4([]() {          // 直接 lambda
        std::cout << "lambda" << std::endl;
        });

    // 等待所有线程完成
    t1.join();
    t2.join();
    t3.join();
    t4.join();

    std::cout << "all threads completed!" << std::endl;
    return 0;
}

注:以 线程t1 简单说明一下

std::thread t1(test); 创建了一个新线程t1,该线程会执行 test 函数。

std::this_thread::get_id() 用于获取当前线程的唯一标识符。

t1.join(); 会阻塞主线程,直到子线程 t1 执行完毕。

带参数的线程函数

可以向线程执行的函数传递参数,传递的参数会被拷贝到新线程的执行环境里面

#include <iostream>
#include <thread>

void printNumber(int num) {
    std::cout << "thread ID " << std::this_thread::get_id() << std::endl;
    std::cout << " print number: " << num << std::endl;
}

int main() {
    int number = 9;
    // 向线程函数传递参数
    std::thread t(printNumber, number); 
    std::cout << "main thread ID " << std::this_thread::get_id() << std::endl;
    t.join();
    return 0;
}

需要注意,如果传递的是引用类型参数,要确保在子线程执行期间该引用所指向的对象是有效的,否则可能导致未定义行为。如果想传递引用,可以使用std::refstd::cref

#include <iostream>
#include <thread>

void changeNumber(int& num) {
	num += 10;
	std::cout << "thread ID " << std::this_thread::get_id() << std::endl;
	std::cout << "number: " << num << std::endl;
}

int main() {
	int number = 5;
	// 使用 std::ref 传递引用
	std::thread t(changeNumber, std::ref(number));
	std::cout << "main thread ID " << std::this_thread::get_id() << std::endl;
	std::cout << "before number: " << number << std::endl;
	t.join();
	std::cout << "after number: " << number << std::endl;
	return 0;
线程分离(detach)

除了 join,还可以使用 detach 将线程与主线程分离,分离后的线程会在后台独立运行,主线程无需等待它结束,也不能再对该线程进行 join 操作。

#include <iostream>
#include <thread>

void test() {
    for (int i = 0; i < 5; ++i) {
        std::cout << i << std::endl;
    }
}

int main() {
    std::thread t(test);
    // 分离线程
    t.detach(); 
    std::cout << "=========" << std::endl;
    // 只会输出 =========
    return 0;
}

注:使用 detach 时要确保分离的线程所访问的资源在该线程生命周期内始终有效,否则可能引发内存访问错误。

同步机制

多线程环境下,为了避免资源竞争(如多个线程同时访问或者修改共享变量),C++11 还引入了一系列同步工具:

1、互斥锁(std::mutex

        用于保护共享资源,同一时间只有一个线程能获取互斥锁并访问共享资源

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

std::mutex m_mutex;
int shared_number = 0;

void test() {
	for (int i = 0; i < 1000; ++i) {
		// 锁定互斥锁
		std::lock_guard<std::mutex> guard(m_mutex);
		shared_number++;
	}
}

int main() {
	std::thread t1(test);
	std::thread t2(test);

	t1.join();
	t2.join();

	std::cout << "shared_number : " << shared_number << std::endl;
	return 0;
}

std::lock_guard 也是一个 RAII(也就是资源获取即初始化)类型,在构造时自动锁定互斥锁,析构时自动解锁,能有效避免忘记解锁导致的死锁问题。

2、条件变量(std::condition_variable

        用于线程间的通信,一个线程可以等待某个条件满足后再继续执行。

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

std::mutex m_mutex;
std::condition_variable m_cv;
bool ready = false;

void worker() {
	std::unique_lock<std::mutex> lock(m_mutex);
	// 等待条件变量满足
	m_cv.wait(lock, [] { return ready; });
	std::cout << "worker thread is running" << std::endl;
}

int main() {
	std::thread t(worker);

	// 模拟一些操作后,等待两秒,设置条件为满足
	std::this_thread::sleep_for(std::chrono::seconds(2));

	{
		std::lock_guard<std::mutex> lock(m_mutex);
		ready = true;
	}
	// 通知等待的线程
	m_cv.notify_one();

	t.join();
	return 0;
}

std::condition_variable 通常和 std::mutex 以及 std::unique_lock 配合使用,

m_cv.wait()①当得到锁的线程执行到wait()函数时,当条件不满足,会原子性地释放得到的锁(确保其他线程有机会得到锁);

②而后当前线程进入阻塞状态,等待被唤醒;

③当该线程被notify()notifyAll()唤醒后,会重新尝试获取锁;

④只有成功重新获取锁后,线程才会从wait()方法返回,继续执行后续代码

3、原子类型(std::atomic

        提供了无锁的原子操作,对于一些简单的共享变量操作(如整数的增减),使用原子类型可以避免加锁带来的性能开销。

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

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

void test() {
    for (int i = 0; i < 1000; ++i) {
        number++;
    }
}

int main() {
    std::thread t1(test);
    std::thread t2(test);

    t1.join();
    t2.join();

    std::cout << "number : " << number << std::endl;
    return 0;
}
小结
  1. 线程管理std::thread创建线程,支持join()(等待结束)、detach()(后台运行),get_id()获取线程标识
  2. 同步机制
    • std::mutex互斥锁,配合lock_guard/unique_lock管理临界区
    • std::condition_variable实现线程等待 / 通知(wait()/notify_one()/notify_all()
    • std::atomic提供无锁原子操作
  1. 核心价值:能够跨平台统一接口,原生支持多线程,融合了现代 C++ 特性(比如 lambda),简化了并发编程
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐