首页 > 编程语言 >[C++11与并发编程]5、使用条件变量和互斥锁实现信号量

[C++11与并发编程]5、使用条件变量和互斥锁实现信号量

时间:2022-12-05 17:08:00浏览次数:47  
标签:11 std int count C++ 信号量 互斥 include wait

使用条件变量和互斥锁实现信号量


layout: post title: 使用条件变量和互斥锁实现信号量 categories: cpp_concurrency description: C++并发编程简介 keywords: c++, 并发编程,std::condition_variable,std::mutex,条件变量,信号量


  • ​使用条件变量和互斥锁实现信号量​
  • ​​keywords: c++, 并发编程,std::condition\_variable,std::mutex,条件变量,信号量​​
  • ​​信号量实现​​
  • ​​测试代码​​

C++11 没有提供信号量,但是可以使用条件变量和互斥锁很容易的实现信号量。信号量是用来在多线程中进行资源同步的。信号量内部维护资源的数量,并且提供2个操作——wait和signal,wait的时候获取资源并减少计数器,signal的时候释放资源并增加计数器。只有当计数器的数目>0的情况下去wait才能够获取到资源。

注意:

使用信号量的一个原则是只有获取资源才wait,释放资源才调用signal!!

信号量实现

#include <condition_variable>
#include <thread>

class semaphore
{
public:
semaphore(int count) :m_counter(count){}
~semaphore(){}

void wait()
{
std::unique_lock<std::mutex> lock(m_mutex);
m_counter--;
// while (m_counter < 0)// 防止假唤醒
// {
// m_cv.wait(lock);
// }
m_cv.wait(lock,[this](){
return this->m_counter >= 0; //
});
}

void signal()
{
std::unique_lock<std::mutex> lock(m_mutex);
if (++m_counter <= 0) // 在执行++之后<=0,表明有其他线程在等待资源,因此执行唤醒
{
m_cv.notify_one();
}
}


int m_counter;
std::condition_variable m_cv;
std::mutex m_mutex;
};

测试代码

下面的示例,我们使用信号量来限制并发数。我们将信号量数目设置为5,线程数量设置为8。线程while循环并进行wait获取资源,只有获取到了资源的线程才会继续往下执行。因此最多同时只有5个线程能获取到资源,未获取到资源的线程将陷入等待,直到其他线程调用signal释放资源,将信号量的值加一。

#include <algorithm>
#include <vector>
#include <atomic>
#include <condition_variable>
#include <thread>
#include <chrono>
#include <iostream>
#include <chrono>
#include "fxtime.h"

int main()
{
semaphore s(5); // 信号量,资源数定义为5,因此最大允许5个资源被同时访问
int task_count = 1000;
int i = 0;
std::vector<int> queue(task_count);
std::transform(queue.begin(), queue.end(), queue.begin(), [&i](int &n) {i++; return i; });
int thread_count = 8; // 线程个数
std::vector<std::thread> threads;
std::mutex m;


int sub_index = 0;
fxtime t;
for (int i = 0; i < thread_count; ++i)
{
auto t = std::thread([&queue, &sub_index,&s,&m, task_count]() {
do
{
s.wait();// 获取资源,这里通过信号量限制同时允许5个线程运行

std::unique_lock<std::mutex> lock(m);
if (sub_index >= task_count)
{
std::cout << "thread return" << std::endl;
return;
}
std::cout << ",q[" << sub_index << "]=" << queue[sub_index] << ";counter = [" << s.m_counter << "]"<< std::endl;
sub_index++;
lock.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(std::rand() % 100+10));
s.signal();// 释放资源
} while (true);
});

threads.push_back(std::move(t));
//s.wait(); // 这里进行wait是一个明显的错误,因为这里并没有获取资源!!!
}

std::cout << ";counter = [" << s.m_counter << "]" << std::endl;
int exit_thread_count = 0;
for (auto& t : threads)
{
t.join();
exit_thread_count++;
std::cout << "exit thread count = " << exit_thread_count << std::endl;
}
std::cout << "dont wait>time espaced:" << t.escaped_miliseconds() << "ms" << std::endl;
std::cout << ";counter = [" << s.m_counter << "]" << std::endl;
return 0;
}

标签:11,std,int,count,C++,信号量,互斥,include,wait
From: https://blog.51cto.com/u_6650004/5913054

相关文章

  • [C++11与并发编程]条件变量在生产者-消费者模型中的使用
    条件变量在生产者-消费者模型中的使用layout:posttitle:条件变量在生产者-消费者模型中的陷阱categories:cpp_concurrencydescription:C++并发编程简介keywords:c+......
  • C++读写二进制文件
    方法一:#include<stdio.h>#include<stdlib.h>#include<fstream>#include<string>//size_treadBinaryFile(constchar*filename,unsignedchar*&data){......
  • C++接口工程实践
    https://zhuanlan.zhihu.com/p/213902091还没有学习完简介:程序开发的时候经常会使用到接口。众所周知,C++语言层面并没有接口的概念,但并不意味着C++不能实现接口的功能。......
  • VMware Fusion 13虚拟机如何安装win 11教程
    VM虚拟机如何安装win11?还不知道如何在VMwareFusion13虚拟机中安装win11的朋友,下面就和小编一起来了解一下!VMwareFusion13虚拟机1、运行VMwareFusion13虚拟机,在......
  • 升级到win11 22h2的体验
    win1122h2更稳定了在win1122h2发布后没多久,我就升级到了这个版本,截止目前已经使用半个月了,谈谈我的使用感受。总体要比之前的版本更稳定,表现为笔记本风扇不会突然响,突然卡......
  • 问题:fatal: unable to access 'https://github.com/XXXXX': GnuTLS recv error (-110)
    问题:fatal:unabletoaccess'https://github.com/XXXXX':GnuTLSrecverror(-110):TheTLSconnectionwasnon-properlyterminated.我遇到了这个问题,感觉关了ssl验......
  • 在c#中调用c++的dll崩溃了,try catch 怎么获取异常?
    在framework框架下,通过添加HandleProcessCorruptedStateExceptionsAttribute属性来解决这个问题,(.netcore1.0到3.1之前,不支持从损坏的进程状态异常中恢复,即trycatch没有......
  • C++ IMPL模式解析(下)
    二进制兼容在上一章结尾处提到了二进制兼容的概念,这里先说说二进制兼容的问题。为什么是二进制兼容简单说,就是我的可执行程序调用你的动态库(so/dll),若动态库发生改动,我......
  • c++ vector resize 和 assign
    resize改变大小resize(n,value),不够的部分填充为valuevector<int>nums{1,2,3,4,5,6};nums.resize(3,100);//size缩小,保持原状->{1,2,3}nums.resi......
  • C++获取一年中所有周信息
    std::map<int,std::pair<CTime,CTime>>YearOfWeek(intyear){std::map<int,std::pair<CTime,CTime>>weekMap;CTimetime(year,1,1,0,0,0);in......