C++多线程编程(真实入门!)

C++多线程详解(全网最全) 在C++学习过程中,要想“更上一层楼”的话,多线程编程是必不可少的一步,前面的文章多半是基础方面的内容,这节的话稍微有点拔高。所以说,我们在看这篇文章的时候,大家需要更多的思考是为什么这么做?这样做的好处是什么?以及多线程编程都可以应用在哪里?话不多说,跟着我一起认真探讨这块内容。传统的C++(C++11标准之前)中并没有引入线程这个概念,在C++11出来之前,如果我们想要在C++中实现多线程,需要借助操作系统平台提供的API,比如Linux的,或者windows下的。 阅读详情

前言

本篇博客使用的库:<windows.h> 提供的线程api(当然是使用操作系统自己提供的线程库的最好了啊)(关于线程函数的>官方文档<)

看博客前需要一些基本条件条件:

  1. 对线程有基本的理解
  2. 简单的C++面向过程编程能力

博客主要内容:

  1. 创造单个简单的线程。
  2. 创造单个带参数的线程。
  3. 如何等待线程结束。
  4. 创造多个线程,并使用互斥量来防止资源抢占。

会使用之后,直接跳到“汇总”,复制模板来用就行
相关博客:实现一个简单的线程池

线程教程

创建一个线程:CreateThread()

  1. 函数声明
//返回值:一个HANDLE类型的值,表示线程的句柄,可用于等待线程等函数
HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES   lpThreadAttributes, // 不重要,一般设置为NULL
  SIZE_T                  dwStackSize,        // 堆栈大小,不重要,一般设置为0,表示使用默认堆栈大小
  LPTHREAD_START_ROUTINE  lpStartAddress,     // 函数指针,传入函数名或指针即可
  __drv_aliasesMem LPVOID lpParameter,        // 参数指针,供函数使用
  DWORD                   dwCreationFlags,    // 不重要,一般设置为0
  LPDWORD                 lpThreadId          // 指针,用于保存线程的id,一般设置为NULL
);]
  1. 使用方法
// 声明线程函数的模板:
DWORD WINAPI threadname(LPVOID lpParamter) // 函数名字可随意
{
	/*
	这里填入你的代码
	*/
	return 0L;
}

// 根据声明的函数创造一个线程
// 若函数没有参数,传入函数名字即可,其它参数参考下方示例
 HANDLE hThread = CreateThread(NULL, 0, threadname, NULL, 0, NULL);
  1. 使用实例
    记得等待线程结束!不然函数(不一定是主函数哦,而是CreatThread所处的函数)结束退出后,会释放资源,导致未结束的线程产生各种奇怪的错误!
#include<iostream>
#include<windows.h>

using namespace std;

// 编写了一个我的线程函数
DWORD WINAPI MyThread(LPVOID lpParamter)
{
	cout << "fuck the multithread !\n";
	return 0L;
}

int main ()
{
	// 创造线程
	CreateThread(NULL, 0, MyThread, NULL, 0, NULL);
	// 记得等待线程结束
	system("PAUSE");
	return 0;
}

运行结果:

fuck the multithread !

创建一个带参线程:lpParameter参数

  1. 关于void指针

lpParamter 跟 void指针使用方法类似,void指针可以指向任何数据,所以我们可以把任何类形指针的值赋给void指针(但不能把void指针的值直接赋给其它类型的指针!)
下方是int 与 void 指针相互转换的例子。

int a = 0;
int *intp = &a;
// int指针 转 void指针
void * voidp = intp; // 合法!不会报错

// void指针 转 int指针
intp = voidp; // 不合法! void* 指针不能直接赋值给 int*指针,会报错!
intp = (int *)voidp// 合法!利用强制类型转换,告诉编译器,voidp指针指向的是int数据。
  1. 直接实例

我假设需要传入一个整形参数,在声明函数时,只需要多一行需要这样的操作:

DWORD WINAPI MyThread(LPVOID lpParamter)
{
	// 把lpParamter当成void指针就完事儿了
	int *a = (int *)lpParamter;
	cout << "I have " << a[0] << " dolors!\n";
	return 0L;
}

而创造函数时候,传入一个整形指针就行了

int main ()
{
	int a = 0;
	int *p = &a;
	// 创造线程,注意我把p指针作为参数传入了,它也就成为了上方函数的lpParamter
	CreateThread(NULL, 0, MyThread, p, 0, NULL);
	// 记得等待线程结束
	system("PAUSE");
	return 0;
}

运行结果:

I have 0 dolors!

至于传入更多的参数,可以自己设计一个struct或者class数据结构,并传入其指针就行了,或者也可以传入数组。
至于返回值,也可以利用传入的指针来接收。

等待指定线程结束:WaitForSingleObject()

这个特别简单,此函数就两个参数,第一个参数是创建线程时可得到的返回值(HANDLE)也就是句柄,第二个参数不用关心,传入INFINITE就行了。

使用实例:

HANDLE hThread = CreateThread(NULL, 0, thread1, NULL, 0, NULL);
// 利用得到的句柄等待线程结束
WaitForSingleObject(hThread, INFINITE);

有了这个函数,再也不用Sleep或者While(1)啦。

多线程资源加锁:CreateMutex()

1.创建多个线程

动动脑子都能想到,直接利用循环或多次调用GreatThread函数不就行了么对吧

代码实例

DWORD WINAPI MyThread(LPVOID lpParamter)
{
	// 把lpParamter当成void指针就完事儿了
	int *a = (int *)lpParamter;
	cout << "I have " << a[0] << " dolors!" << endl;
	return 0L;
}

int main()
{
	int a[10];

	for (int i = 0; i < 10; i++)
	{
		a[i] = i;
		HANDLE hThread = CreateThread(NULL, 0, MyThread, a + i, 0, NULL);
	}
	system("PAUSE");
	return 0;
}

但是,直接运行程序,你会发现输出结果特别诡异!顺序完全乱掉了,换行也乱掉了。

I have I have I have 8I have 7I have 5I have 1I have 3 dolors!4 dolors!
2 dolors! dolors!
 dolors!
 dolors!
 dolors!
I have 6I have  dolors!


9 dolors!
I have 0 dolors!

动动脑子也能知道,线程几乎是同时运行的,谁想输出就输出了,管你是不是刚输出到了一半。

所以我们就加锁,使 “输出” 这个资源,只能在一个时间内被单个线程使用

  1. 为资源加锁

创建方法:

// 声明一个句柄
HANDLE cout_mutex;
// 创建一个锁
cout_mutex = CreateMutex(NULL, FALSE, NULL);

使用方法:

// 等待其它线程释放锁,并获取锁的使用权
WaitForSingleObject(cout_mutex, INFINITE);

// 获取锁之后,只要没有解锁,其它线程就会阻塞在WaitForSingleObject()语句。
做一些工作(使用需要互斥的资源等)

// 解锁!
ReleaseMutex(cout_mutex);

使用实例:

HANDLE cout_mutex;

DWORD WINAPI MyThread(LPVOID lpParamter)
{
	// 把lpParamter当成void指针就完事儿了
	int *a = (int *)lpParamter;
	WaitForSingleObject(cout_mutex, INFINITE);
	cout << "I have " << a[0] << " dolors!" << endl;
	ReleaseMutex(cout_mutex);
	return 0L;
}

int main()
{
	int a[10];
	cout_mutex = CreateMutex(NULL, FALSE, NULL);
	for (int i = 0; i < 10; i++)
	{
		a[i] = i;
		HANDLE hThread = CreateThread(NULL, 0, MyThread, a + i, 0, NULL);
	}
	system("PAUSE");
	return 0;
}

运行结果:

可以看出输出正常了。

I have 0 dolors!
I have 1 dolors!
I have 7 dolors!
I have 5 dolors!
I have 4 dolors!
I have 6 dolors!
I have 3 dolors!
I have 9 dolors!
I have 2 dolors!

指定线程运行核心:SetThreadAffinityMask()

现在的cpu一般都是多核的了(任务管理器->性能 -> CPU 即可看到信息),所以有时候需指定线程到某个核心,可以更主动的对cpu资源进行分配。

  1. 函数声明
DWORD_PTR SetThreadAffinityMask(HANDLE hThread, DWORD_PTR dwThreadAffinityMask);
  1. 使用方法:

第一个参数是线程的句柄(HANDLE),第二个参数用来指定CPU核心

比如,你要指定进程到第0个CPU上,则mask=0×01
第1个CPU:mask=0×02
第2个CPU:mask=0×04 (注意不是0×03)
第3个CPU:mask=0×08
以此类推。
如果要指定多个CPU:
比如第0、1个:mask=0×03
第1、2个:mask=0×06
以此类推。
如果CPU个数不足,则会进行取模操作。比如一共4个CPU,则mask=0×0010则和0×01一样
(此段文字转自其它博客,但找不到源链接,就不贴出来了)

  1. 代码实例:
// 绑定到第三个核心
HANDLE hThread = CreateThread(NULL, 0, MyThread, a + i, 0, NULL);
SetThreadAffinityMask(hThread, 0x08);

汇总

线程函数

DWORD WINAPI threadname(LPVOID lpParamter) // 函数名字可随意
{
	int *a = (int *)lpParamter;
	return 0L;
}

创建线程

HANDLE hThread = CreateThread(NULL, 0, threadname, NULL, 0, NULL);

等待线程

WaitForSingleObject(hThread , INFINITE);

互斥量

HANDLE cout_mutex;
cout_mutex = CreateMutex(NULL, FALSE, NULL);

WaitForSingleObject(cout_mutex, INFINITE);
ReleaseMutex(cout_mutex);
C++多线程入门教程(一) 本文为作者在多线程入门学习时的笔记与心得,如有不对之处,欢迎大家指正 1. 线程(Thread) 线程是操作系统进行CPU调度的最小单位。我们在电脑上所使用的单个程序在操作系统中被叫做进程,为了提高进程的执行速度和并发性,一般的进程都会有一个以上的线程。进程和进程之间一般互不影响,但对于同一个进程的线程们来说,只要有一个线程崩溃,整个进程变回崩溃。 2. C++中的线程 2.1 主线程 在学习使用... 阅读详情

相关推荐

C++23 多线程详解(全网最全,代码均已实测)

本文全面详解C++23多线程特性,基于GCC 14.2与-std=c++23编译通过,经ThreadSanitizer验证无数据竞争。涵盖std::jthread、std::stop_token、std::latch/barrier/counting_semaphore、std::atomic::wait、std::print及std::move_only_function等新特性,修复旧版线程池死锁与资源泄漏问题。强调避免detach,推荐使用自动管理生命周期的jthread,并提供完整可运行示例,确保跨

安徽锐锋科技-沐雨潇竹 1万+

C++网络编程进阶

C/S模型在企业级的软件开发中非常常见,高并发网络通讯更是很多项目的核心模块,学好socket 网络编程显得尤为重要,本课程分为TCP/IP 协议、socket基础与进阶的异步通讯模型三个部分,通过浅显易懂的代码与讲解,让你的C++网络编程能力得到质的飞跃,具备开发高并发服务器的能力!

SAP ABAP实战:手把手教你用BAPI_BILLINGDOC_CREATEMULTIPLE批量开票(附完整代码与避坑指南)

本文详细解析了SAP ABAP中BAPI_BILLINGDOC_CREATEMULTIPLE批量开票的全流程,包括参数配置、事务控制、错误处理及性能优化。通过实战案例和完整代码示例,帮助开发者高效处理大批量发票生成任务,避免常见陷阱,提升开发效率。

weixin_34101914的博客 265

C++多线程

一、多线程简介 C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是<atomic> ,<thread>,<mutex>,<condition_variable>和<future>。 <atomic> :该头文主要声明了两个类, std::atomic 和 std::atomic_flag,另外还声明了一套 C 风格的原子类型和与 C 兼容的原子操作的函数。 <thread>:该头文件主要声明了 std::th

钟离默的个人博客 9034

笔记汇总 | 斯坦福 CS229 机器学习

本文为斯坦福大学 2014 秋季 CS229 机器学习课程学习笔记本文主体部分转载自黄海广博士,文末已给出,大家有兴趣可以直接访问笔记首页,下载对应课程资料及作业代码。

ReturnTmp的博客 2462

如何读懂CiteSpace图谱?科研小白必看的节点颜色/年轮/聚类解读手册

本文详细解析CiteSpace图谱的核心视觉元素,包括节点颜色、年轮和聚类标识,帮助科研人员准确解读数据分析结果。通过生物医学案例展示如何从图谱中识别关键文献和研究趋势,提供五步系统解读法和常见错误规避策略,助力科研小白快速掌握文献计量分析技巧。

weixin_29179311的博客 314

C++多线程编程(真实入门)

https://blog.youkuaiyun.com/Kprogram/article/details/89472995

hanxiaoyong_的博客 2669

CS5523实战:如何用国产芯片完美替代LT8911设计MIPI转eDP电路(附原理图)

本文详细介绍了使用国产芯片CS5523完美替代LT8911进行MIPI转eDP电路设计的实战经验。文章从芯片选型、核心特性对比入手,深入剖析了电源时钟设计、MIPI/eDP接口的PCB布局与信号完整性要点,并提供了完整的原理图参考和调试排错指南,为硬件工程师实现国产化替代提供了清晰可行的方案。

yhn4567890的博客 1140

C++ 多线程编程

C++11之前,window和linux平台分别有各自的多线程标准,使用C++编写的多线程往往是依赖于特定平台的。Window平台提供用于多线程创建和管理的win32 api;Linux下则有POSIX多线程标准,Threads或Pthreads库提供的API可以在类Unix上运行;在C++11新标准中,可以简单通过使用thread库,来管理多线程。thread库可以看做对不同平台多线程API的一层包装;因此使用新标准提供的线程库编写的程序是跨平台的。

梦心之魂的博客 3519

MFC工具栏增加EditBox和Button

1. 在资源视图中增加EditBox, Button控件,ID分别为ID_EDIT_SEED, ID_BTN_SEED 2. 在CMainFrame中增加成员变量 CMFCToolBarEditBoxButton *m_editSeed; CMFCToolBarButton *m_btnSeed; 3. 在CMainFrame::OnCreate中创建控件 m_editSeed = new CMFCToolBarEditBoxButton(ID_EDIT_SEED, GetCmdMgr()-&.

学习是为了探索这个世界的本质 802

【问题解决】解决 Python `PermissionError` 权限不足:文件/进程/端口全场景修复

本文总结了Python程序中常见的权限问题及解决方案,包括文件、进程和端口权限错误。文件权限问题通常由文件占用、权限不足或路径错误引起;进程问题多因权限不足或系统限制;端口问题则与端口占用、防火墙或特权端口相关。解决方案提供了详细的代码实现:文件权限管理器类(FilePermissionManager)包含检查权限(check_permission)、修复权限(fix_permission)、安全写入(safe_write)和安全删除(safe_delete)等方法,通过异常处理和临时文件等技术确保操作安全

博客 357

Windows下C++多线程编程(入门实例)

  多线程在编程中有相当重要的地位,我们在实际开发时或者找工作面试时总能遇到多线程的问题,对多线程的理解程度从一个侧面反映了程序员的编程水平。   其实C++语言本身并没有提供多线程机制(当然目前C++ 11新特性中,已经可以使用std::thread来创建线程了,因为还没有系统地了解过,所以这里不提了。),但Windows系统为我们提供了相关API,我们可以使用他们来进行多线程编程。 创建线...

a3192048的博客 6万+

UEFI 基础教程 (零) - 目录

UEFI 基础教程 (十八) — UEFI Build Process简单分析。UEFI 基础教程 (十五) — 获取UEFI MemoryMap。UEFI 基础教程 (六)   —  PROTOCOL 简单使用。UEFI 基础教程 (十)   —  FileIO 简单使用。UEFI 基础教程 (一)   —  搭建UEFI开发环境。UEFI 基础教程 (九)   —  EVENT 简单使用。UEFI 基础教程 (七)   —  HOB 简单使用。UEFI 基础教程 (八)   —  PCD 简单使用。..

技术联盟 1536

P多线程编程基础.cpp

本文介绍了C++多线程编程的核心技术,包括线程创建与管理、参数传递、同步机制等关键内容。通过具体代码示例,展示了如何使用std::thread创建线程、通过互斥锁(mutex)解决数据竞争、利用条件变量实现线程协作,以及构建简单线程池的方法。文章还探讨了原子操作和线程局部存储(TLS)等进阶技术,并提供了并行计算的实际案例。最后强调了多线程编程中的线程安全、死锁预防和性能优化等注意事项,为开发高效并发程序提供了实用指导。

m0_66709139的博客 970

Linux C/C++ or 嵌入式面试之《C/C++笔面试系列》(10) C++ 前置后置增减运算符重载形式与比较

C语言的++、–运算符在此不讨论。 文章目录1、前置后置增减运算符重载的形式2、前置和后置运算符的性能比较 1、前置后置增减运算符重载的形式 自增运算符“++”和自减运算符“–”分别包含两个版本。即运算符前置形式(如 ++x)和运算符后置形式(如 x++),这两者进行的操作是不一样的。因此,当我们在对这两个运算符进行重载时,就必须区分前置和后置形式。C++根据参数的个数来区分前置和后置形式。如果按照通常的方法来重载 ++ 运算符(即作为成员函数重载时不带参数,或者作为非成员函数重载时带有一个参数),那么重载

二进制君 5831

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

c++多线程编程

C++ 的多线程编程提供了强大的工具来实现并发执行。通过使用。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 1083

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

C++多线程编程

等。使用的头文件包括:<thread>, <mutex>, <condition_variable>, <future>等头文件。内容包括:1. 线程创建2. 互斥锁(mutex)的使用3. 条件变量(condition variable)的使用4. 异步操作(async, future)

cape_NO_7的博客 1057

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

windows下多线程编程: c++ , multithreading and dev-cpp

在Windows下用dev-cpp实现Linux下使用c++进行多线程编程: Dev-cpp开源中国的下载地址http://www.oschina.net/p/dev+cplusplus 一、下载Windows版本的pthread 目前最新版本是:pthreads-w32-2-8-0-release.exe。 主页地址:http://sourceware.org/pt...

a121124的博客 450

探索C++的响应式编程:深入了解REACT-CPP

探索C++的响应式编程:深入了解REACT-CPP 在现代软件开发中,异步编程和事件驱动是不可或缺的部分,尤其是对于高并发系统而言。今天,我们为您介绍一个专注于提升C++编程中事件循环体验的开源库——REACT-CPP。这不仅是一个工具,更是一种让您的C++应用轻盈起舞的秘密武器。 项目介绍 REACT-CPP,一个利用C++11引入的Lambda函数作为通知机制的事件循环库,一旦文件描述符或计时...

gitblog_00529的博客 1007

探索C++编程的无限可能:Learn CPP项目推荐

探索C++编程的无限可能:Learn CPP项目推荐 项目介绍 Learn CPP 是一个专注于C++编程语言的开源项目,旨在为初学者和有经验的开发者提供一个全面的学习和实践平台。无论你是刚刚接触编程,还是希望深入了解C++的高级特性,这个项目都能满足你的需求。通过丰富的代码示例和详细的文档,Learn CPP帮助你逐步掌握C++的核心概念和应用技巧。 项目技术分析 语言特性 面向对象编程:C+...

gitblog_00317的博客 795

C++语言的多线程编程

C++语言的多线程编程为开发者提供了有效利用多核处理器、提升程序效率的工具。在实际开发中,深入理解和掌握C++中的多线程机制能够帮助开发者更好地应对复杂的并发场景。然而,多线程编程也带来了诸多挑战,合理使用同步手段、遵循最佳实践,是确保程序稳定和高效运行的关键。未来,随着C++标准的不断发展,多线程编程将会有更为强大的工具和库等待我们去探索和运用。

2501_90231419的博客 1503

C++多线程编程入门教程

在本文中,我们介绍了 C++ 多线程编程的基本概念和语法,包括线程的创建、同步和互斥等。通过学习这些知识,你可以开始在你的 C++ 项目中使用多线程编程,充分发挥现代多核处理器的性能。在开始 C++ 多线程编程之前,我们需要了解一些基本的概念。其次,多线程编程需要考虑线程之间的同步和互斥问题,以避免数据竞争和不一致性。无论是开发高性能的服务器应用程序,还是编写复杂的图形用户界面,多线程编程都能为我们带来巨大的好处。在多线程编程中,线程之间的同步和互斥是非常重要的。的函数,该函数将在一个新的线程中执行。

@Ysjt丨深的博客 喜欢就留下哦 531

FreeRTOS_cpp11:为嵌入式开发带来C++11多线程支持

FreeRTOS_cpp11:为嵌入式开发带来C++11多线程支持 项目介绍 FreeRTOS_cpp11 是一个开源项目,它为 FreeRTOS 实时操作系统提供 C++11 标准的多线程支持。这意味着开发者可以在嵌入式系统中使用 C++11 中的 std::thread、std::mutex、std::condition_variable、std::chrono、std::future 等高级...

gitblog_00675的博客 1293

Multithreading-Cpp-Course:掌握现代C++并发编程的不二选择

Multithreading-Cpp-Course:掌握现代C++并发编程的不二选择 项目介绍 在现代软件开发领域,多线程编程是一个至关重要的技能。它不仅能提升程序的性能和响应速度,还能有效利用多核处理器的能力。Multithreading-Cpp-Course 是一套针对现代C++并发编程的教程源码,源自知名的在线教育平台Udemy上的课程 "Learn Multithreading ...

gitblog_01108的博客 705

C++多线程编程:从入门到实战

C++多线程编程通过并发执行提升程序性能,核心在于线程创建、同步机制及并发/并行概念。C++11引入的<thread>支持线程管理,需注意join()或detach()的生命周期。同步机制包括互斥锁(std::mutex)、条件变量(std::condition_variable)和原子操作(std::atomic),分别解决数据竞争、线程通信和无锁访问问题。多线程适用于计算密集型(如矩阵运算)和I/O密集型任务,但需警惕数据竞争、死锁等挑战,通过锁顺序、原子操作等方式规避。合理使用多线程能显著

2202_75382767的博客 1062
上一篇: c++实现线程池(真实入门!)
下一篇: STL - priority_queue(优先队列)用法总结
Korpse
博客等级 码龄9年 115粉丝 25原创
评论 18
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值