简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
1.前言
本篇目的:理解C++之mutex互斥量与lambda函数应用总结。
2.lambda函数概念与用法
在C++中,lambda表达式是一种匿名函数的语法形式,可以在需要函数对象的地方直接定义和使用函数。lambda表达式的实现原理是通过创建一个匿名的函数对象,这个函数对象重载了operator()
运算符,使得可以像函数一样进行调用。
lambda表达式的一般语法形式如下:
[capture-list] (parameter-list) -> return-type { function-body }
其中,capture-list
是捕捉列表,用于指定lambda表达式中使用的外部变量。parameter-list
是参数列表,用于指定lambda表达式的参数。return-type
是返回类型,用于指定lambda表达式的返回值类型。function-body
是函数体,包含了lambda表达式的实际执行逻辑。
Lambda表达式的应用原理是通过简化函数对象的定义和使用,可以更方便地编写匿名的函数和进行函数式编程。它常用于以下几个场景:
- 函数传递:可以直接将lambda表达式作为函数参数,以简化回调函数的定义和传递。
- 算法逻辑:可以直接在算法函数中使用lambda表达式,以定义算法的具体执行逻辑。
- 数据转换:可以通过lambda表达式进行数据的转换和过滤,实现数据处理的灵活性和可读性。
3.mutex函数概念与用法
互斥锁(mutex)是一种用于同步线程的机制。它可以确保在多个线程访问共享资源时,只有一个线程能够执行临界区代码,以防止并发访问导致的数据竞争问题。
互斥锁的实现原理通常涉及操作系统提供的底层同步原语或硬件指令。以下是一个简单的概述:
-
创建互斥锁:在C++中,可以使用
std::mutex
类来创建互斥锁对象。在创建时,该对象处于未锁定状态。 -
加锁(Lock):当一个线程想要进入临界区时,它首先必须尝试获取互斥锁的所有权。如果互斥锁未被锁定,则该线程会成功地获得锁,并进入临界区。如果互斥锁已经被其他线程锁定,则当前线程会被阻塞,直到该锁被释放为止。
-
临界区操作:一旦线程获得了互斥锁的所有权,它就可以执行临界区内的操作。这些操作通常是对共享资源进行读取或写入。
-
解锁(Unlock):在线程完成临界区操作后,它必须释放互斥锁,以便其他线程能够获取锁并进入临界区。通过调用互斥锁对象的
unlock()
方法,线程可以释放锁。
使用互斥锁可以有效地确保在任何给定时刻只有一个线程可以访问共享资源,从而避免数据竞争和并发访问的问题。然而,过度使用互斥锁可能会导致线程间的竞争,从而影响性能。因此,在设计并发应用程序时,需要仔细权衡使用互斥锁的粒度和范围。
4.operator()函数概念与用法
在C++中,operator()
是一种函数调用运算符(function call operator),也被称为仿函数(functor)。它允许将一个类的对象像函数一样进行调用,使得对象可以具有函数的行为。
operator()
的实现原理涉及到类的重载运算符和函数调用机制。以下是一些关键的原理:
-
重载运算符:在C++中,运算符可以被重载,也就是可以重新定义运算符的行为。通过重载运算符,可以指定在使用运算符时编译器应该执行的操作。
-
类的成员函数:
operator()
是一个类的成员函数,因此它只能在类的对象上进行调用。它可以像普通的成员函数一样,访问类的成员变量和其他成员函数。 -
函数调用机制:当我们使用对象来调用
operator()
时,编译器会将其解析为函数调用,并将调用参数传递给这个函数。调用operator()
的语法类似于调用函数的语法。 -
实现灵活性:通过实现
operator()
,我们可以将一个对象实例化为可以像函数一样使用的可调用对象。这种灵活性使得我们可以将对象作为函数对象传递给算法或者将其用于其他需要函数作为参数的场合。
使用operator()
可以为类对象带来函数的行为特征,使得这些对象可以被直接调用,并进行一些定义的操作。通过重载运算符,我们可以自定义operator()
的行为,使其在对象被调用时执行特定的操作逻辑。
5.应用实例
v1.0 mutex与lambda函数应用
#include <iostream>
#include <memory>
#include <mutex>
class TEST {
public:
int count = 100;
std::shared_ptr<TEST> comp;
};
int main() {
std::mutex mState;
std::shared_ptr<TEST> comp;
auto checkAllocated = [&]() {
std::unique_lock<std::mutex> lock(mState);
comp = std::make_shared<TEST>();
return comp->count;
};
int result = checkAllocated();
std::cout << "count: " << result << std::endl;
return 0;
}
v2.0 operator()无参仿函数例子
#include <iostream>
class TEST {
public:
int operator()(int x){
this->count = x;
return x;
}
int count;
};
int main() {
TEST test;
int result = test(5);
std::cout << "data value: " << result << std::endl;
return 0;
}
v3.0 operator()有一个参数仿函数例子
#include <iostream>
class TEST {
public:
int operator()(int x){
this->count = x;
return x;
}
int count;
};
int main() {
TEST test;
int result = test(5);
std::cout << "data value: " << result << std::endl;
return 0;
}
注意:operator()仿函数不能使用构造函数初始化列表方式,以下用法是错误的。
class TEST {
public:
int operator()(int x): count(x){
return x;
}
int count;
};
4.0 mutex、operator、lambda函数组合应用
#include <iostream>
#include <memory>
#include <mutex>
class TEST {
public:
int count = 100;
std::shared_ptr<TEST> comp;
};
template <typename T>
class Mutexed {
public:
explicit Mutexed(T data) : m_data(std::move(data)) {
printf("xxx--------->%s(), line = %d\n",__FUNCTION__,__LINE__);
}
//Mutexed定义了自己的operator()函数,可以定义对象,对象像函数一样使用。
template <typename F>
auto operator()(F&& func) {
std::lock_guard<std::mutex> lock(m_mutex);
return std::forward<F>(func)(m_data);
}
private:
T m_data;
std::mutex m_mutex;
};
int main() {
//1.使用shared_ptr指向TEST的智能指针comp,make_shared创建TEST对象并赋值给comp
std::shared_ptr<TEST> comp = std::make_shared<TEST>();
comp->count = 200;
//2.调用嗯Mutexed构造函数,并传入指向TEST的智能指针类型mState,并且将comp赋值给mState.
Mutexed<std::shared_ptr<TEST>> mState(comp);
auto checkAllocated = [&]() {
//mState是Mutexed的operator()函数,这里相当于 调用mState(参数)回调函数,传入参数即可。它在实例化出mState时,已经将comp传给了m_data,这里调用state->count,相当于调用m_data->count.
return mState([](const std::shared_ptr<TEST>& state) {
return state->count;
});
};
int result = checkAllocated();
std::cout << "count: " << result << std::endl;
return 0;
}