当前位置: 首页 > news >正文

c++线程

pthread(部分内容来自菜鸟教程)

创建线程

创建一个 POSIX 线程:

#include <pthread.h>
pthread_create (thread, attr, start_routine, arg) 

pthread_create 创建一个新的线程,并让它可执行。

参数:

  • thread :指向线程标识符指针
  • attr :一个不透明的属性对象,可以被用来设置线程属性。可以指定线程属性对象,也可以使用默认值 NULL。
  • start_routine :线程运行函数起始地址,一旦线程被创建就会执行。
  • arg :运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。

终止线程

#include <pthread.h>
pthread_exit (status) 

向线程传递参数

在线程回调中传递任意的数据类型,因为它指向 void。

使用 pthread_create() 函数创建了 5 个线程,并接收传入的参数。每个线程打印一个 “Hello Runoob!” 消息,并输出接收的参数,然后调用 pthread_exit() 终止线程。

#include <iostream>
#include <cstdlib>
#include <pthread.h>using namespace std;#define NUM_THREADS     5struct thread_data{int  thread_id;char *message;
};void *PrintHello(void *threadarg)
{struct thread_data *my_data;my_data = (struct thread_data *) threadarg;cout << "Thread ID : " << my_data->thread_id ;cout << " Message : " << my_data->message << endl;pthread_exit(NULL);
}int main ()
{pthread_t threads[NUM_THREADS];struct thread_data td[NUM_THREADS];int rc;int i;for( i=0; i < NUM_THREADS; i++ ){cout <<"main() : creating thread, " << i << endl;td[i].thread_id = i;td[i].message = (char*)"This is message";rc = pthread_create(&threads[i], NULL,PrintHello, (void *)&td[i]);if (rc){cout << "Error:unable to create thread," << rc << endl;exit(-1);}}pthread_exit(NULL);
}

连接和分离线程

pthread_join (threadid, status) 
pthread_detach (threadid) 

pthread_join() 子程序阻碍调用程序,直到指定的 threadid 线程终止为止。当创建一个线程时,它的某个属性会定义它是否是可连接的(joinable)或可分离的(detached)。只有创建时定义为可连接的线程才可以被连接。如果线程创建时被定义为可分离的,则它永远也不能被连接。

#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>using namespace std;#define NUM_THREADS     5void *wait(void *t)
{int i;long tid;tid = (long)t;sleep(1);cout << "Sleeping in thread " << endl;cout << "Thread with id : " << tid << "  ...exiting " << endl;pthread_exit(NULL);
}int main ()
{int rc;int i;pthread_t threads[NUM_THREADS];pthread_attr_t attr;void *status;// 初始化并设置线程为可连接的(joinable)pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);for( i=0; i < NUM_THREADS; i++ ){cout << "main() : creating thread, " << i << endl;rc = pthread_create(&threads[i], NULL, wait, (void *)&i );if (rc){cout << "Error:unable to create thread," << rc << endl;exit(-1);}}// 删除属性,并等待其他线程pthread_attr_destroy(&attr);for( i=0; i < NUM_THREADS; i++ ){rc = pthread_join(threads[i], &status);if (rc){cout << "Error:unable to join," << rc << endl;exit(-1);}cout << "Main: completed thread id :" << i ;cout << "  exiting with status :" << status << endl;}cout << "Main: program exiting." << endl;pthread_exit(NULL);
}

同步实现–锁

lock有很多实现的方式,linux这里使用的是mutex,由于mutex本身是结构体,所以声名的时候别忘了init一下。

#include "pthread.h"pthread_mutex_t mutex; //这里要保证是global var,
pthread_mutex_init(&mutex, NULL); //init mutex,pthread_mutex_lock(&mutex); //准备进入临界区// critical section //pthread_mutex_unlock(&mutex); //释放锁,别的线程可能要使用
pthread_mutex_destroy(&mutex); // 销毁锁,锁不能在用了

Condition vatiables(cv)

cv的含义其实有点偏向于MPI的思想,传递消息;可以让threads wait,也可以notify or broadcast线程让他们起来干活。主要的操作有一下三种:

phtread_cond_init();pthread_cond_wait(&theCV,&somelock); //这里sleep线程的同时也将somelock释放掉了,要不其他线程无法取得lock就没办法执行(甚至是叫醒它了)
pthread_cond_signal(&theCV); 
pthread_cond_boardcast(&theCV);

在临界区中处理写share量的时候,需要保证不同线程对其的访问是可控的,否则可能在不同线程中读取到的写share量不一致进而影响CV的工作,因为一般情况下临界区中的写share量就是我们CV工作中的重要判断量。因此,虽然这个条件相对严格,但是是有必要的。

semaphore

这个东西可以看作是lock的一个自然延申。也就是一个资源可以同时被多少执行单元使用。我们之前讲到的lock就可以看做是一个binary semaphore。这里就只是简要的谈谈,因为这个东西使用的时候很让人头大,弄不好就会死锁。而且虽然semaphore属于POSIX标准,但是严格来讲的话,它不属于pthread。

#include <semaphore.h>sem_t sem;
sem_init(&sem);
sem_wait(&sem);// critical sectionsem_post(&sem);
sem_destroy(&sem);

semaphore可以控制同一个时间有多少thread可以访问临界区,需要注意的就是上面声明–释放的匹配关系不要忘记。

std::thread

创建线程

通过 detach() 函数,将子线程和主线分离,子线程可以独立继续运行,即使主线程结束,子线程也不会结束。

#include <iostream>
#include <thread>
using namespace std::literals::chrono_literals;
using namespace std;void test() {cout << "Hello World" << endl;
}int main() {std::thread t1(test);t1.detach();this_thread::sleep_for(10ms); // c++ 17// 低于C++17使用这行代码  this_thread::sleep_for(chrono::milliseconds(10));return 0;
}

传递参数

join() 函数可以在当前线程等待线程运行结束。

#include <iostream>
#include <thread>
using namespace std::literals::chrono_literals;
using namespace std;void test(int Id,string name) {cout << "Hello World" << endl;cout << "Id : " <<Id<<" Name : "<<name<< endl;
}int main() {std::thread t1(test,12,"haha");t1.join();this_thread::sleep_for(10ms); // c++ 17// 低于C++17使用这行代码  this_thread::sleep_for(chrono::milliseconds(10));return 0;
}

线程休眠

using namespace std::literals::chrono_literals;
// 让当前线程睡眠 10 毫秒
this_thread::sleep_for(10ms);
// 低于C++17使用这行代码  this_thread::sleep_for(chrono::milliseconds(10));
// 让当前线程睡眠 5 秒
this_thread::sleep_for(5s);

condition_variable

使用 condition_variable 实现生产者和消费者的实验,通过 wait 进入线程等待,知道有其它的线程把当前线程唤醒。

当 std::condition_variable 对象的某个 wait 函数被调用的时候,它使用 std::unique_lock(通过 std::mutex) 来锁住当前线程。当前线程会一直被阻塞,直到另外一个线程在相同的 std::condition_variable 对象上调用了 notification 函数来唤醒当前线程。

当前线程调用 wait() 后将被阻塞(调用wait()前先获取线程锁std::unique_lockstd::mutex lock(g_mutex))同时会自动调用 unlock() 释放锁(g_mutex),直到另外某个线程调用 notify_*(g_con.notify_one()、g_con.notify_all()) 唤醒了当前线程。唤醒当前线程时wait() 函数也是自动调用 lock()(g_mutex:加锁,进入临界区),使得 g_mutex 的状态和 wait 函数被调用时相同。

在线程被阻塞时,该函数会自动调用 lck.unlock() 释放锁,使得其他被阻塞在锁竞争上的线程得以继续执行。另外,一旦当前线程获得通知(notified,另外某个线程调用 notify_* 唤醒了当前线程),wait() 函数也是自动调用 lck.lock(),使得 lck 的状态和 wait 函数被调用时相同。

#include <iostream>
#include <thread>
#include <list>
using namespace std::literals::chrono_literals;
using namespace std;std::mutex g_mutex; // 线程锁
condition_variable g_con; // cvlist<int> products;void test() {int product_id = 0;while (true) {products.push_back(++product_id);cout << "products 生产: " << product_id << endl;std::unique_lock<std::mutex> lock(g_mutex);  // 进入临界区// 通知消费者消费g_con.notify_one(); 						// 唤醒 g_con.wait(lock)// g_con.notify_all(); // 唤醒所有线程(多个线程同时使用 g_con g_mutex)lock.unlock(); 								// 提前释放锁,供其他线程进入临界区if (product_id > 50) {break;}this_thread::sleep_for(2ms);}
}int main() {std::thread t1(test);while (true) {std::unique_lock<std::mutex> lock(g_mutex); // 离开代码作用域后自动解锁if (products.empty()) {cout << "没有产品,等待" << endl;// 进入等待,知道有新产品g_con.wait(lock);  // 释放锁 线程阻塞;唤醒时,自动加锁,与调用wait函数之前一行if(!products.empty()){int product_id = products.front();products.pop_front();cout << "消费产品 " << product_id << endl;this_thread::sleep_for(2ms);if (product_id > 50) break;                }}}t1.join();return 0;
}

std::unique_lock<std::mutex> 出作用域后会自动解锁

thread_local

C++11中提供了thread_local,thread_local定义的变量在每个线程都保存一份副本,而且互不干扰,在线程退出的时候自动销毁。

#include <iostream>
#include <thread>
using namespace std::literals::chrono_literals;
using namespace std;
thread_local int t_l_counter = 0;void test() {cout << "flag1 t_l_counter: " << t_l_counter << endl;t_l_counter = 2;
}int main() {t_l_counter = 1;std::thread t1(test);t1.join();cout << "flag2 t_l_counter: " << t_l_counter << endl;return 0;
}

同步锁

如果需要同一时间只有一个线程在test函数中执行代码,那么就要加锁,lock() 用于加锁,而unlock() 解锁。

#include <iostream>
#include <thread>
using namespace std::literals::chrono_literals;
using namespace std;
std::mutex g_mutex;void test() {g_mutex.lock();cout << "task start thread ID: " << this_thread::get_id() << endl;this_thread::sleep_for(10ms);cout << "task end thread ID: " << this_thread::get_id() << endl;g_mutex.unlock();
}
int main() {std::thread t1(test);std::thread t2(test);std::thread t3(test);t1.join();t2.join();t3.join();return 0;
}

除了std::mutex(非递归的互斥量),还有std::timed_mutex(带超时的非递归互斥量),std::recursive_mutex(递归互斥量)、std::recursive_timed_mutex(带超时的递归互斥量)。

lambda在线程中的使用

lambda 的语法

[capture](parameters) mutalble->return-type{statement};

编译器会自动生成一个匿名类,该类重载了 () 运算符。

int id = 0;
auto f = [id]() mutable {cout << "id: " << id << endl;++id;
}

capture

  • [] :什么也不捕获
  • [=] : 按值的方式捕获所有变量
  • [&] : 按引用方式捕获所有变量
  • [boo] : 值捕获boo的值
  • [=,&a] : 按值捕获所有局部变量,按引用捕获变量a
  • [=,&a,&b,&c] : 同上
  • [&,a] : 按引用捕获所有局部变量,按值捕获方式捕获a
  • [&,a,b,c] : 同上
  • [this] : 在成员函数中,直接捕获this指针

mutable

值捕获后,在匿名函数中对该值是不能做修改的,如果想要做修改,必须加上 mutable 关键字,并且在匿名函数中做的修改结果在函数外是不会生效的。

parameters

参数列表也是可以将外部的值传递给匿名函数内部的;与正常函数的形参一样。

return-type

对于编译器能自动推导的返回类型,可以省略 return-type,但是如果无法推导的类型,就必须添加上返回类型

当函数不止一个return语句时,就需要加上返回类型了

线程中使用lambda

#include <iostream>
#include <thread>
using namespace std;
int main() {std::thread t1([]{cout << "task start thread ID: " << this_thread::get_id() << endl;}};t1.join();return 0;
}

相关文章:

c++线程

pthread(部分内容来自菜鸟教程) 创建线程 创建一个 POSIX 线程&#xff1a; #include <pthread.h> pthread_create (thread, attr, start_routine, arg) pthread_create 创建一个新的线程&#xff0c;并让它可执行。 参数&#xff1a; thread &#xff1a;指向线程标…...

【Docker】02-安装mysql

参考教程&#xff1a; https://www.bilibili.com/video/BV1Qa4y1t7YH/?p5&spm_id_frompageDriver&vd_source4964ba5015a16eb57d0ac13401b0fe77 docker安装Mysql 1、拉取最新版本的镜像 docker pull mysq:latestl 2、运行mysql服务 docker run --name mysql -e MYSQL_…...

JAVA每日小知识(关于excel下载时插入和stream流遍历优化)

1、在windows系统下启动rocketmq操作&#xff1a; 在bin目录下使用cmd 分别输入 start mqnamesrv.cmd start mqbroker.cmd -n 127.0.0.1:9876 autoCreateTopicEnabletrue 2、在stream流中需要new对象时&#xff0c;可能会出现new很多对象堆积在堆中&#xff0c;这是需要用try,…...

阿里后端开发:抽象建模经典案例

0.引言 在互联网行业&#xff0c;软件工程师面对的产品需求大都是以具象的现实世界事物概念来描述的&#xff0c;遵循的是人类世界的自然语言&#xff0c;而软件世界里通行的则是机器语言&#xff0c;两者间跨度太大&#xff0c;需要一座桥梁来联通&#xff0c;抽象建模便是打…...

【车载以太网测试从入门到精通】——DoIP BootLoader刷写测试(含CAPL源码)

系列文章目录 文章目录 系列文章目录前言一、DoIP刷写环境搭建二、DoIP刷写工程使用方法三、DoIP刷写CAPL源码四、刷写工程下载链接前言 DoIP概述: DoIP(Diagnostic communication over InternetProtocol),基于IP网络的汽车诊断协议。DoIP技术可实现本地诊断、远程诊断、空…...

RK开发板的USB连接(Ubuntu)

一、安装连接工具 sudo apt-get install putty 二、启动putty工具 sudo putty 三、连接usb&#xff0c;并查看相关的信息 # 查看接入的是否有usb ls /dev/tty* 显示如下&#xff1a;&#xff08;含有usb接口&#xff1a; /dev/ttyUSB0&#xff09; /dev/tty /dev/tty23 /d…...

Redis-Cluster集群的部署(详细步骤)

一、环境准备 本次实操为三台机器&#xff0c;关闭防火墙和selinux 注:规划架构两种方案&#xff0c;一种是单机多实例&#xff0c;这里我们采用多机器部署 三台机器&#xff0c;每台机器上面两个redis实例&#xff0c;一个master一个slave&#xff0c;第一列做主库&#xff…...

Vulnhub: Hogwarts: Bellatrix靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.228 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.228访问80端口 查看源码&#xff0c;提示ikilledsiriusblack.php和文件包含的参数名file 漏洞利用 ikilledsiriusblack.p…...

机器学习(吴恩达第一课)

课程链接 文章目录 第一周1、机器学习定义2、监督学习(Supervised learning)1、回归(Regression)2、分类(Classification) 3、无监督学习(Unsupervised learning)4、线性回归模型5、代价函数6、梯度下降(Gradient descent)1、学习率2、用于线性回归的梯度下降 第二周(多维特征…...

固定资产管理怎么改革

固定资产管理改革需要考虑以下几个方面&#xff1a; 建立完善的管理制度和流程&#xff1a;制定固定资产管理的规章制度&#xff0c;明确各部门的职责和任务&#xff0c;规范资产采购、登记、领用、保管、维修、报废等流程。 采用先进的资产管理软件&#xff1a;通过采用先进的…...

【js】防抖和节流的使用场景和区别:

文章目录 一、防抖 &#xff08;多次触发 只执行最后一次&#xff09;二、节流 &#xff08;规定时间内 只触发一次&#xff09;三、防抖和节流的使用场景【1】防抖&#xff08;debounce&#xff09;【2】节流&#xff08;throttle&#xff09; 一、防抖 &#xff08;多次触发 …...

Blazor前后端框架Known-V1.2.14

V1.2.14 Known是基于C#和Blazor开发的前后端分离快速开发框架&#xff0c;开箱即用&#xff0c;跨平台&#xff0c;一处代码&#xff0c;多处运行。 Gitee&#xff1a; https://gitee.com/known/KnownGithub&#xff1a;https://github.com/known/Known 概述 基于C#和Blazo…...

港陆证券:五日线破位怎么看?

在股票交易中&#xff0c;五日线是个重要的技术指标之一&#xff0c;它能够反映出最近的商场趋势。假如五日线破位&#xff0c;这意味着商场呈现了趋势反转&#xff0c;出资者需求注重趋势改动&#xff0c;并采取相应的出资战略。 首先&#xff0c;咱们来看看五日线破位的原因…...

睿趣科技:抖音小店多久可以做起来

随着社交媒体的迅猛发展&#xff0c;抖音成为了全球最受欢迎的短视频平台之一&#xff0c;吸引了数以亿计的用户。在抖音上&#xff0c;人们不仅可以分享自己的生活、才艺和创意&#xff0c;还可以创业经营抖音小店。但是&#xff0c;很多人都想知道&#xff0c;一个抖音小店到…...

onnx 模型切割掉conv后面的节点,设置输出层名称和最后节点名称一致,设置输出层shape和输出节点一致.

某些模型最后卷积层之后的算子不适合在推理引擎里面跑&#xff0c;切割掉conv后面的算子&#xff0c;在cpu上实现有比较好的性能&#xff0e; 包含&#xff1a; &#xff11;&#xff0e;获取onnx中间节点的shape的示例 &#xff12;&#xff0e;增加onnx模型输出&#xff0c;设…...

泛型的学习

泛型深入 泛型&#xff1a;可以在编译阶段约束操作的数据类型&#xff0c;并进行检查 泛型的格式&#xff1a;<数据类型> 注意&#xff1a;泛型只能支持引用数据类型 //没有泛型的时候&#xff0c;集合如何存储数据//如果我们没有给集合指定类型&#xff0c;默认认为…...

L1-061 新胖子公式(Python实现) 测试点全过

前言&#xff1a; {\color{Blue}前言&#xff1a;} 前言&#xff1a; 本系列题使用的是&#xff0c;“PTA中的团体程序设计天梯赛——练习集”的题库&#xff0c;难度有L1、L2、L3三个等级&#xff0c;分别对应团体程序设计天梯赛的三个难度。更新取决于题目的难度&#xff0c;…...

潜艇来袭(Qt官方案例-2维动画游戏)

一、游戏介绍 1 开始界面 启动程序&#xff0c;进入开始界面。 2 开始新游戏 点击菜单&#xff1a;File》New Game &#xff08;或者CtrlN&#xff09;进入新游戏。 开始新游戏之后&#xff0c;会有一个海底的潜艇&#xff0c;和水面舰艇对战。 计算机&#xff1a;自动控制…...

50ETF期权开户平台(0门槛期权开户指南)

50ETF期权开户平台比较好的有&#xff1a;期权馆&#xff0c;期权科普馆&#xff0c;小熊期权&#xff0c;期权酱&#xff0c;财顺财经&#xff0c;财顺期权等&#xff0c;都是国内前十的期权分仓平台&#xff0c;下文为大家结算50ETF期权开户平台&#xff08;0门槛期权开户指南…...

leaflet · 关于轨迹移动

1.引入 import MovingMarker from "../src/utils/MovingMarker"; 2.MovingMarker.js内容 import L from "leaflet"; import eventBus from ../util/eventBus; L.interpolatePosition function(p1, p2, duration, t) {var k t/duration;k (k > 0) ? …...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...