文章目录
🌕多线程
🌙线程的创建
std::thread 线程名(执行函数,要传递的变量1,...)
🌙启动线程
线程名.join();
当你在一个线程上调用 join 方法时,当前线程将等待这个线程执行完毕,然后再继续执行后续的代码。
🌙使用互斥锁对变量进行锁定
std::mutex mtx; // 互斥锁,用于保护共享数据
int max_num = 10;
# 在执行函数中加入:
std::lock_guard<std::mutex> lock(mtx); // 自动加锁和解锁
🌙输出奇数偶数案例
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
std::mutex mtx; // 互斥锁,用于保护共享数据
void print_even(int max_num) {
for (int i = 0; i <= max_num; i += 2) {
std::lock_guard<std::mutex> lock(mtx); // 自动加锁和解锁
std::cout << "Even: " << i << std::endl;
}
}
void print_odd(int max_num) {
for (int i = 1; i <= max_num; i += 2) {
std::lock_guard<std::mutex> lock(mtx); // 自动加锁和解锁
std::cout << "Odd: " << i << std::endl;
}
}
int main() {
int max_num = 10;
// 创建两个线程,分别执行 print_even 和 print_odd 函数
std::thread even_thread(print_even, max_num);
std::thread odd_thread(print_odd, max_num);
// 等待两个线程完成
even_thread.join();
odd_thread.join();
std::cout << "Threads completed!" << std::endl;
return 0;
}
🌕线程池
预先创建一组线程来处理任务,从而避免频繁创建和销毁线程的开销。
线程池中的线程可以重复使用,当有新的任务需要执行时,线程池会选择一个空闲线程来处理该任务,而不需要重新创建一个新的线程。这种方式可以提高性能和资源利用率。
🌙线程池模板
⭐include/thread_pool.h
#ifndef THREAD_POOL_H
#define THREAD_POOL_H
#include <vector> // 用于存储线程的向量
#include <queue> // 用于存储任务的队列
#include <thread> // 用于创建和管理线程
#include <mutex> // 用于线程间同步
#include <condition_variable> // 用于线程间的条件变量
#include <functional> // 用于存储任务函数
#include <future> // 用于处理异步任务结果
class thread_pool {
public:
thread_pool(size_t); // 构造函数,初始化线程池
template<class F, class... Args>
auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>; // 向线程池中添加任务
~thread_pool(); // 析构函数,销毁线程池
private:
std::vector<std::thread> workers; // 工作线程
std::queue<std::function<void()>> tasks; // 任务队列
std::mutex queue_mutex; // 任务队列的互斥锁
std::condition_variable condition; // 任务队列的条件变量
bool stop; // 停止标志
};
#include "thread_pool.tpp" // 包含模板实现文件
#endif // THREAD_POOL_H
⭐include/thread_pool.tpp
// thread_pool.tpp
template<class F, class... Args>
auto thread_pool::enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> {
using return_type = typename std::result_of<F(Args...)>::type; // 获取任务的返回类型
auto task = std::make_shared<std::packaged_task<return_type()>>( // 创建一个包装任务
std::bind(std::forward<F>(f), std::forward<Args>(args)...) // 绑定任务函数及其参数
);
std::future<return_type> res = task->get_future(); // 获取任务的 future 对象
{
std::unique_lock<std::mutex> lock(queue_mutex); // 加锁任务队列
if(stop) // 如果线程池已经停止,抛出异常
throw std::runtime_error("enqueue on stopped thread_pool");
tasks.emplace([task](){ (*task)(); }); // 将任务添加到任务队列中
}
condition.notify_one(); // 通知一个等待的线程
return res; // 返回任务的 future 对象
}
⭐src/thread_pool.cc
#include "thread_pool.h" // 包含线程池头文件
thread_pool::thread_pool(size_t threads) // 构造函数,初始化线程池
: stop(false) { // 初始化停止标志为 false
for(size_t i = 0; i < threads; ++i) // 创建指定数量的工作线程
workers.emplace_back( // 将线程放入 workers 向量中
[this] { // 使用 lambda 表达式
for(;;) { // 无限循环,等待任务
std::function<void()> task; // 定义任务函数
{
std::unique_lock<std::mutex> lock(this->queue_mutex); // 加锁任务队列
this->condition.wait(lock, // 等待任务队列不为空或停止标志为 true
[this]{ return this->stop || !this->tasks.empty(); });
if(this->stop && this->tasks.empty()) // 如果停止标志为 true 且任务队列为空,退出循环
return;
task = std::move(this->tasks.front()); // 获取任务队列中的任务
this->tasks.pop(); // 移除任务队列中的任务
}
task(); // 执行任务
}
}
);
}
thread_pool::~thread_pool() { // 析构函数,销毁线程池
{
std::unique_lock<std::mutex> lock(queue_mutex); // 加锁任务队列
stop = true; // 设置停止标志为 true
}
condition.notify_all(); // 通知所有等待的线程
for(std::thread &worker: workers) // 等待所有工作线程完成
worker.join();
}
🌙使用线程池模板开启三个线程执行数字相加
实现total = number_a + number_b + number_c,而number_a的值为从1从加到10,number_b的值为从1加到50,number_c的值为从1加到100, 是不是用三个线程分别计算number_a,number_b,number_c比较好?
⭐main.cc
#include <iostream> // 标准输入输出流
#include "thread_pool.h" // 包含线程池头文件
int calculate_sum(int start, int end)
{
int sum = 0;
for (int i = start; i <= end; ++i)
{
sum += i;
}
return sum;
}
int main()
{
thread_pool pool(3); // 创建包含 3 个线程的线程池
// 使用线程池计算 number_a, number_b 和 number_c
auto future_a = pool.enqueue(calculate_sum, 1, 10); // 计算 number_a 的值
auto future_b = pool.enqueue(calculate_sum, 1, 50); // 计算 number_b 的值
auto future_c = pool.enqueue(calculate_sum, 1, 100); // 计算 number_c 的值
// 获取计算结果
int number_a = future_a.get();
int number_b = future_b.get();
int number_c = future_c.get();
// 计算总和
int total = number_a + number_b + number_c;
// 打印结果
std::cout << "number_a: " << number_a << std::endl;
std::cout << "number_b: " << number_b << std::endl;
std::cout << "number_c: " << number_c << std::endl;
std::cout << "total: " << total << std::endl;
return 0;
}
⭐cmakelists.txt
cmake_minimum_required(VERSION 3.10)
# 设置项目名称
project(multithreading_test)
# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 包含头文件目录
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
# 添加可执行文件
add_executable(multithreading_test main.cc src/thread_pool.cc)
# 链接线程库
find_package(Threads REQUIRED)
target_link_libraries(multithreading_test Threads::Threads)
set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/install/multithreading_test)
install(TARGETS multithreading_test DESTINATION ./) # 把可执行文件安装到CMAKE_INSTALL_PREFIX当前目录下
⭐build.sh
#!/bin/bash
# build.sh
# 使用 set -e 命令,如果任何命令返回非零状态,脚本将立即退出
set -e
# 设置编译器路径
GCC_COMPILER=/usr
# 获取当前目录
ROOT_PWD=$( cd "$( dirname $0 )" && pwd )
# 设置build的位置
BUILD_DIR=${ROOT_PWD}/build
# 设置install的位置
INSTALL_DIR=${ROOT_PWD}/install
# 如果存在 install 目录,则删除它
if [[ -d "${INSTALL_DIR}" ]]; then
echo "Install directory exists. rm -f install"
rm -rf ${INSTALL_DIR}
fi
# 如果没有build目录则创建它
if [[ ! -d "${BUILD_DIR}" ]]; then
mkdir -p ${BUILD_DIR}
fi
# 检查build目录是否为空
if [[ "$(ls -A ${BUILD_DIR})" ]]; then
# 如果build目录不为空,则执行make clean
echo "Build directory is not empty. make clean"
make -C ${BUILD_DIR} clean
fi
# 检查是否存在CMakeCache.txt文件
if [[ -f "${BUILD_DIR}/CMakeCache.txt" ]]; then
# 删除CMakeCache.txt文件
echo "CMakeCache.txt found. rm CMakeCache.txt"
rm -f "${BUILD_DIR}/CMakeCache.txt"
fi
cd ${BUILD_DIR}
cmake .. \
-DCMAKE_C_COMPILER=${GCC_COMPILER}/bin/gcc \
-DCMAKE_CXX_COMPILER=${GCC_COMPILER}/bin/g++
make -j$(nproc)
make install
# 回到当前目录
cd -
# # 修改install中lib_shared目录名为lib
# mv install/yolov5_rtsp_rv1126/lib_shared install/yolov5_rtsp_rv1126/lib
####################################################### adb_push操作 #####################################################
# 示例变量
VAR1=1
VAR2=0
#如果 1==1则执行adb相关命令
if [ "$VAR1" -eq "$VAR2" ]; then
# 条件为真时执行的命令
echo "1==1,exec follow adb push commond."
# 获取输入参数
PARAM1="1"
PARAM2="1"
# 检查输入参数数量
if [ "$#" -e 2 ]; then
# echo "Usage: $0 <is yolov5_rtsp_rv1126 exist> <is /tmp/lib exist>"
# 获取输入参数
PARAM1="$1"
PARAM2="$2"
fi
# adb操作
REMOTE_PATH="/tmp"
REMOTE_LIB_PATH="${REMOTE_PATH}/lib"
REMOTE_TARGET_PATH="${REMOTE_PATH}/yolov5_rtsp_rv1126"
RV1126_LD_LIBRARY_PATH=/oem/usr/lib:/oem/lib:/oem/usr/lib:/oem/lib:
# 如果第一个参数为1,则表明yolov5_rtsp_rv1126存在
if [ "$PARAM1" -eq 1 ]; then
echo "Found $REMOTE_TARGET_PATH. Deleting..."
adb shell rm -r "$REMOTE_TARGET_PATH"
echo "$REMOTE_TARGET_PATH has been deleted."
else
echo "$REMOTE_TARGET_PATH does not exist."
fi
# 把编译好的install推送到板端
adb push install/yolov5_rtsp_rv1126/ ${REMOTE_PATH}
# 打印操作
echo "adb push install/yolov5_rtsp_rv1126/ ${REMOTE_PATH}"
# 检查远程目录是否存在,如果存在则跳过,不存在则创建它,并对libeasymedia.so进行软链接
if [ "$PARAM2" -eq 1 ]; then
echo "Remote directory ${REMOTE_LIB_PATH} already exists."
else
echo "Remote directory $REMOTE_LIB_PATH does not exist. Creating..."
adb shell mkdir -p $REMOTE_LIB_PATH
echo "Remote directory $REMOTE_LIB_PATH created."
# 推送共享库到远程目录
adb push ${SHARED_LIB_DIR}/* ${REMOTE_LIB_PATH}
# 打印操作
echo "adb push ${SHARED_LIB_DIR}/* ${REMOTE_LIB_PATH}"
# 设置/tmp/lib为动态链接库,必须用单引号,否则会使用本机的$LD_LIBRARY_PATH
adb shell export LD_LIBRARY_PATH=/tmp/lib:${RV1126_LD_LIBRARY_PATH}
# 打印操作
echo "adb shell export LD_LIBRARY_PATH=/tmp/lib:$RV1126_LD_LIBRARY_PATH"
# 设置libeasymedia.so.1.0.1的软链接为libeasymedia.so.1
adb shell ln -sf ${REMOTE_LIB_PATH}/libeasymedia.so.1.0.1 ${REMOTE_LIB_PATH}/libeasymedia.so.1
# 打印操作
echo "adb shell ln -s ${REMOTE_LIB_PATH}/libeasymedia.so.1.0.1 ${REMOTE_LIB_PATH}/libeasymedia.so.1"
fi
else
# 条件为假时执行的命令
echo "1==0, only exec cmake and make install."
fi
🌕其它
🌙获取硬件并发数
int main() {
unsigned int n = std::thread::hardware_concurrency();
std::cout << "Number of concurrent threads supported: " << n << std::endl;
return 0;
}
🌙互斥锁
⭐什么是互斥锁?
互斥锁(Mutex,Mutual Exclusion)是一种同步机制,用于防止多个线程同时访问共享资源,从而避免数据竞争和保持数据一致性。
1万+

被折叠的 条评论
为什么被折叠?



