💻文章目录
- 📄前言
 - C++线程库
 - 创建线程
 - 互斥量
 - mutex
 - lock_guard
 - unique_lock
 
- 同步机制
 - condition_variable
 - C++20 信号量 的工作原理。
 
- 📓总结
 
📄前言
在C++线程库推出之前,如果要实现跨平台多线程,那么我们就得需要直到每个平台的线程API的知识,这无疑对每个程序员都是不小的挑战,毕竟大部分人都不愿意去一一学习这些接口,而线程库的推出,封装了线程底层的实现,不仅提高了代码的可移植性,还减少了C++的学习压力。
C++线程库
创建线程
thread是c++11引进的线程管理机制,主要用于封装系统底层的线程API, 例如windows的 CreateThread 和linux的pthread_create,从而提高代码的可移植性。
- thread的函数原型与参数
 
template <class Function, class... Args>
explicit thread (Function&& f, Args&&... args);
// 创建一个线程,可用lamda、函数指针+参数等形式
id get_id() const noexcept;	
bool joinable() const noexcept;
 
- 成员函数 
  
- get_id:返回线程id
 - joinable:检查一个线程是否可以被回收。
 - join:回收线程的资源,防止僵死线程,如果线程没有执行完,则阻塞等待。
 - detach:与主线程分离,线程执行完毕后自动回收资源。
 
 
函数使用示例:
void func(std::string str)
{
	std::cout << std::this_thread::get_id() << std::endl;
    for(int i = 0; i < 10; i++)
    {
        std::cout << str << ":" << i << std::endl;
    }
}
int main() {
    std::thread t1(func, "thread 1");
    std::thread t2([]() { func("thread 2"); });
    t1.join();
    t2.join();
    return 0;
}
 
互斥量
mutex
mutex 是c++线程库最基础的互斥机制,用于保护临界资源不被多个线程同时访问,mutex 只提供了基础的锁和解锁接口。
class mutex {
public:
	lock();
	unlock();
	try_lock();	
}
 
- 成员函数: 
  
- lock:锁定互斥量,只允许一个线程访问,
 - unlock:解锁互斥量,
 - try_lock:尝试锁定互斥量,如果互斥量被锁定则不阻塞,一直检查锁是否解锁(返回0),直到锁被解锁(返回1)。
 
 
lock_guard
lock_guard 与互斥量一起使用,提供一种RAII风格的管理机制(析构时自动调用unlock),避免忘记解锁而导致死锁的情况。
template <class Mutex> class lock_guard;
 
unique_lock
unique_lock 的基础用法与lock_guard一样,但比它提供了更多的功能,如控制锁的时间、方式,对条件变量的支持,以及可被移动(不可被复制)
template <class Mutex> class unique_lock;
template <class Clock, class Duration>
  bool try_lock_until (const chrono::time_point<Clock,Duration>& abs_time);
template <class Rep, class Period>
  bool try_lock_for (const chrono::duration<Rep,Period>& rel_time);
  
// 复制构造
unique_lock (const unique_lock&) = delete;
// 移动构造
unique_lock (unique_lock&& x);
 
- 常用成员函数: 
  
- try_lock:不阻塞地申请锁
 - try_lock_for:与chrono类一起使用,等待指定的时间后去申请锁,申请失败继续等待。
 - try_lock_until:在指定的时间到底前都能一直申请锁,时间到达但没获得锁,则继续执行其他任务。
 
 
函数使用示例:
void fun_c(std::string name, int n)
{
    std::unique_lock<std::timed_mutex> lock(t_mtx, std::defer_lock);
    if(lock.try_lock_for(std::chrono::seconds(n)))
    {
        std::cout << name << " ";
        for(int i = 0; i < 10; ++i)
        {
            std::unique_lock<std::mutex> lock(mtx);
            std::cout << counter++ << std::endl;
        }
        std::this_thread::sleep_for(std::chrono::seconds(6));
    }
    else 
        std::cout << "can't lock" << std::endl;
    std::cout << name << "end" << std::endl;
}
int main() {
    std::thread t1(fun_c, "thread 1:", 2);
    std::thread t2(fun_c, "thread 2:", 2);
    t1.join();
    t2.join();
    return 0;
}
 
同步机制
condition_variable
condition_variable 是对系统条件变量的包装,用于实现线程直接的等待通知机制,需要与互斥量一起使用,拥有两大功能 wait 和 notify。
class condition_variable;
 
- 成员函数: 
  
- wait:线程在这个函数中等待,直到接受到信号通知,和unique_lock 一样,它也有wait_for 和 wait_until,需要与互斥量一起使用。线程等待时会将锁给解锁。
 - notify_once:通知一个等待着的线程,并唤醒它。
 - notify_all:通知所有在wait等待着的线程,唤醒它们。
 
 
函数使用
std::condition_variable cv;
std::mutex mtx;
bool flag = false;
int counter = 0;
void producer(std::string name)
{
    // 通过条件变量可以控制线程的执行顺序
    std::cout << name << std::endl;
    for(int i = 0; i < 10; ++i)
    {
        {
            std::unique_lock<std::mutex> lock(mtx);
            while(flag)	
                cv.wait(lock);	// wait时会自动将锁解锁
            std::cout << ++counter << std::endl;
            flag = !flag;
            cv.notify_one();
        }
		std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}
void consumer(std::string name)
{
    std::cout << name << std::endl;
    for(int i = 0; i < 10; ++i)
    {
        {
            std::unique_lock<std::mutex> lock(mtx);
            while(!flag)
                cv.wait(lock);
            std::cout << ++counter << std::endl;
            flag = !flag;
            cv.notify_one();	//唤醒一个线程
        }
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}
int main() {
    std::thread t1(producer, "thread 1");
    std::thread t2(consumer, "thread 2");
    t1.join();
    t2.join();
    return 0;
}
 
C++20 信号量 的工作原理。
在c++20中新增了轻量级的线程控制机制——信号量,我们可以为信号量设定最大值与初始值,当信号量达到0或者最大值时,线程会阻塞,直到其不为0或最大值。
// 头文件 <semaphore>
template< std::ptrdiff_t LeastMaxValue = /* implementation-defined */ >
class counting_semaphore;
//尚未定义ptrdiff_t 一般为int,用于定义信号量的最大值。
 
- 成员函数: 
  
- release:释放信号量,将信号量计数加 1 ,如果计数达到最大值则阻塞等待,知道信号量被消费。
 - acquire:申请信号量,将信号量的计数减 1 ,当计数为零或为满则阻塞等待,直到其他线程释放信号量。
 - try_acquire:尝试去减少信号量的计数,如果信号量为零则返回false,并且一直申请信号量直至成功。一般用于信号量消费较快的场景。
 
 
函数使用
int counter = 0;
void producer(std::string name)
{
    
    std::cout << name << std::endl;
    for(int i = 0; i < 10; ++i)
    {
        sem.try_acquire();	//信号量也可以用来代替锁
        std::cout << ++counter << std::endl;
        sem.release();
    }
}
void consumer(std::string name)		
{
    std::cout << name << std::endl;
    for(int i = 0; i < 10; ++i)
    {
        sem.try_acquire();
        std::cout << ++counter << std::endl;
        sem.release();
    }
}
int main() {
    std::thread t1(producer, "thread 1");
    std::thread t2(consumer, "thread 2");
    t1.join();
    t2.join();
    return 0;
}
 
📓总结
| 功能类别 | 关键特性 | 描述 | 
|---|---|---|
| 线程管理 | std::thread | 抽象系统级线程,简化线程创建和管理。 | 
| 基础同步 | mutex, lock_guard, unique_lock | 提供基本的线程同步机制,如互斥锁,以及自动锁管理工具。 | 
| 高级同步 | condition_variable | 使线程能在特定条件下挂起和唤醒,优化资源利用和线程协调。 | 
| C++20新特性 | counting_semaphore | 引入信号量概念,为线程提供更细粒度的控制,如限流并发操作。 | 
📜博客主页:主页
📫我的专栏:C++
📱我的github:github











![[23年蓝桥杯H题] 合并石子](https://img-blog.csdnimg.cn/direct/b4144db664274035acedfce51ebead4d.png)







