C++ 多线程开发知识汇总

前言

作为偏底层的语言来说,在什么情况下使用什么,必须有理有据,那么这就考察了一个C++程序员对底层知识的理解。往往程序的健壮性就是建立在这个层面上的。多线程的开发在C++项目中是重中之重,如果你想对大量数据对运算并且采用分而治之的算法思想(这里暂且不考虑GPU的并行计算咯,处理器必须是多核的才有效果哟),那么选择多线程,如果你需要在QT中防止GUI线程因为计算而出现的卡段现象,那么需要多线程,如果你想编写高性能的网络服务,一样需要多线程。

线程

线程是什么

套用比较官方的一句话:是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

sleep(0)函数

想要理解sleep函数,就需要理解多线程的五种状态,这里上一张来自百度百科的图:
在这里插入图片描述

根据这张图的理解,我们知道调用sleep是告诉CPU说,我要等一下,然后其他线程干一会吧。那sleep(0),其实是告诉cpu说,我立刻就去就绪队列了,让其他线程一起来竞争cpu吧。死循环防止cpu100%,见代码

while(true){
//do something
	sleep(0);
};

线程的用法

下面用C++标准库里的函数,来展示其代码实现

创建

面向对象风格:

std::thread* pMyThread = new std::thread(std::bind(&类名::函数, 对象指针, 参数));

函数式编程风格

std::thread* pMyThread =  new std::thread([=](){
//do something
});

线程对象产生后,默认是运行状态,并且与主线程是分离(detach)的。

如何优雅的结束线程

线程的资源是创建在进程之上,主线程结束,进程释放资源,那这个时候子线程的资源也要保证释放,不然会引起异常的退出。这这个时候,jion函数就派上了用场。一般类内的线程对象是在析构函数调用下面的代码

if(pMyThread && pMyThread.jionable())
{
	pMyThread.jion();
	delete pMyThread;
	pMyThread = nullptr;
}

线程同步

线程同步指的是线程之间“协同”,即线程之间按照规定的先后次序运行。
不同系统提供了不同方式或者系统API,其中:windows线程同步的方式主要有四种:互斥对象、事件对象、信号量以及关键代码段(windows特有)。互斥对象、事件对象、信号量属于内核对象,利用内核对象进行线程同步时,速度较慢,但利用这些内核对象可以实现多个进程间的线程同步。由于咱们公司基本上都是Qt框架,而且本身Qt也提供了对应的同步手段,对window就不做深入的讨论了。卑微的提供一个Qt框架下的链接:https://blog.csdn.net/u011555996/article/details/124353809。linux下的同步方式如下
在这里插入图片描述

如果对底层实现兴趣,请移至https://www.zhihu.com/question/332113890/answer/762392859(图片也是来源这儿哦),反正就是对内核里面一个原子性的东西,捣鼓来捣鼓去。

C++标准库的线程同步实现

其实标准库已经提供了完善的同步手段,编码过程中可以不直接调用系统API。这样写的代码具有很好的跨平台性。

互斥量std::mutex

少用mutex.lock()和mutex.unlock()。标准库提供了unique_lock、shared_lock互斥量包装器,他们搭配使用,即体现了RAII 的机制,又可以实现读写锁。示例:

std::mutex mutex;
std::unique_lock<std::mutex> lock(mutex);//写锁 优先级高,写的时候,不可以读写

std::mutex mutex;
std::shared_lock<std::mutex> lock(mutex);//读锁 可以同时读,也就是遇到这个代码同时可以进入

条件变量

在C++11中,我们可以使用条件变量(condition_variable)实现多个线程间的同步操作;当条件不满足时,相关线程被一直阻塞,直到某种条件出现,这些线程才会被唤醒。可以用到消费者生产者模式中。
生产者示例:

void SocketMessageSender::SendMessage(websocketpp::connection_hdl hdl,std::string msg)
{
    std::unique_lock<std::mutex> lock(this->m_Mutex);
    SenderTS senderTs;
    senderTs.hdl = hdl;
    senderTs.msg = msg;
    m_SenderMsgList.push_back(senderTs);//发送消息到队列
    m_Condition.notify_all();//通知激活线程
}

消费者示例

void SocketMessageSender::SendMsgThread()
{
    while (true)
    {
        std::unique_lock<std::mutex> lock(this->m_Mutex);
      	//wait的时候,锁是释放的,不然生产者线程如何进入!
        this->m_Condition.wait(lock, [this]() {return !this->m_HostProtocolControl || !this->m_SenderMsgList.empty();});
        if (!this->m_HostProtocolControl)//条件满足后,lock锁住m_SenderMsgList队列的访问权限,继续执行
        {
            return;//保证线程可正常退出
        }
        SenderTS senderTs;
        senderTs = m_SenderMsgList.front();
        m_pWebSocketServer->sendMessage(senderTs.hdl,senderTs.msg);
        LOGS_INFO("tasknode") << "回复信息:" << senderTs.msg.c_str();
        m_SenderMsgList.pop_front();
    }
}

信号量

操作系统中的PV操作相同,由于我极少用信号量,所以就不高谈阔论了,说了也是抄的它的https://blog.csdn.net/qq_46615150/article/details/114519037,

思考

基本数据类型如int 、float、bool要不要加锁呢?

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在软件开发多线程面试中,可能会遇到以下几个经典问题: 1. 线程和进程的区别是什么?请举例说明。 2. 什么是线程同步?有哪些常见的线程同步方法? 3. 什么是线程死锁?如何避免线程死锁? 4. 什么是线程池?为什么要使用线程池? 5. 什么是线程安全?如何保证线程安全? 6. 什么是信号量和互斥量?它们有什么区别? 7. 什么是线程调度?常见的线程调度算法有哪些? 8. 什么是线程阻塞和线程唤醒?如何实现线程的阻塞和唤醒? 9. 什么是线程间通信?有哪些常见的线程间通信方式? 10. 如何创建和销毁线程?有哪些常见的线程创建和销毁的方法? 请注意,以上问题只是软件开发多线程面试可能会遇到的一部分问题,具体面试题目还取决于面试官的要求和特定岗位的要求。建议在面试前仔细准备和复习相关知识,以便能够回答面试官的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++后台开发面试题总结(涉及C++基础、多线程多进程、网络编程等)](https://blog.csdn.net/qq_42302962/article/details/123433951)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值