windows下c++编写多线程

Windows多线程控制台程序 学习笔记 Windows多线程控制台程序目的:学习和掌握如何编写Windows多线程控制台程序。通过编写程序,加深对进程和线程关系的理解,掌握多线程程序的执行和编写技巧。设计要求:写一个单进程多线程的Windows控制台程序,该程序在一个进程内建立N个线程来执行指定的任务。N由命令行传递给系统。Win32控制台程序中,主函数的格式如:Void main(int argc,char *argv[]),可以获取命令行参数。通过VC++“工程/设置”的C/C++属性页设置应用程序为“MTD”多线程。利用win32 阅读详情

一.进程

首先来看进程,它是一个正在运行的程序的实例,是一个程序在其自身的地址空间的一次执行活动。进程是资源申请、调度、和独立运行的基本单位。进程有两部分组成:

1操作系统用来管理进程的内核对象,内核对象是系统用来存放关于进程的统计信息的地方,它是操作系统内部分配的一块内存块,该内存块是一种数据结构,其成员负责维护该对象的各种信息。

2地址空间,它包含所有可执行模块、dll模块的代码和数据,也包含动态内存分配的空间。

二.线程

真正完成代码执行的是线程,而进程只是线程的容器,或者说是线程的执行环境。

每个进程至少拥有一个线程,来执行进程的地址空间的代码。当创建一个进程时,操作系统自动创建该进程的第一个线程,称为主线程,也就是执行main或WinMain函数的线程,也可以把main或WinMain函数看作是主线程的进入点函数,然后主线程可以创建其他线程。

线程由两部分组成:

1线程的内核对象,操作系统用它来对线程实施管理,内核对象是系统用来存放关于线程的统计信息的地方

2线程栈,它用于维护线程在执行代码时需要的所有函数参数和变量。

操作系统为每一个运行线程安排一定的CPU时间—时间片,

创建线程可以使用系统提供的API函数CreateThread来完成,该函数原型如下:

HANDLECreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINElpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);

lpThreadAttributes:指向SECURITY_ATTRIBUTES的指针,这里可以传递NULL,让该线程使用默认的安全性。

dwStackSize 设置线程初始栈的大小,如果为0,或小于默认值的大小,那么默认将使用与调用该函数的线程相同的栈空间大小。

lpStartAddress 指向应用程序定义的THREAD_START_ROUTINE类型的函数的指针,这个函数将由新线程执行,表明新线程的起始地址。我们知道main函数是主线程的起始地址,同样,新创建的线程也需要有一个入口函数,这个函数的地址就由此参数决定,,这就要求在程序中定义一个函数作为新线程的入口函数,遵照下述声明形式

DWORD WINAPIThreadFunc(LPVOID lpParameter);

新线程入口函数有一个LPVOID类型的参数,并且返回值是DWORD类型,函数名称可以改变。

lpParameter,通过这个参数给新创建的线程传递参数,该参数提供了一种将初始化值传递给线程的手段。

dwCreationFlags,设置用于控制线程创建的附加标记,他可以是两个值中的一个:CREATE_SUSPENDED或0,。如果该值为CREATE_SUSPENDED,那么线程创建后处于暂停状态,直到程序调用了ResumeThread函数为止,如果该值为0,那么线程在创建后立即执行。

lpThreadId 该参数是一个返回值,指向一个变量,用来接收线程ID。当创建一个线程后,系统会为线程分配一个ID。

三.线程同步

看一个例子,火车站售票模拟程序。

int index = 0;

int tickets = 100;

HANDLE hMutex = NULL;

CRITICAL_SECTION g_cs = NULL;

HANDLE hEvent = NULL;

DWORD WINAPI Func1(LPVOID pParam)

{

   while(true)

   {

      WaitForSingleObject(hMutex, INFINITE);

//    WaitForSingleObject(hEvent,INFINITE);

//    EnterCriticalSection(&g_cs);

      if(tickets> 0)

      {

        Sleep(1);

        cout<<"thread1 sell tickets:"<<tickets--<<endl;

      }

      else

        break;

      ReleaseMutex(hMutex);

//    SetEvent(hEvent);

//    LeaveCriticalSection(&g_cs);

   }

   return0;

}

DWORD WINAPI Func2(LPVOID pParam)

{

   while(true)

   {

      WaitForSingleObject(hMutex,INFINITE);

//    WaitForSingleObject(hEvent,INFINITE);

//    EnterCriticalSection(&g_cs);

      if(tickets> 0)

      {

        Sleep(1);

        cout<<"thread2 sell tickets:"<<tickets--<<endl;

      }

      else

        break;

      ReleaseMutex(hMutex);

//    SetEvent(hEvent);

//    LeaveCriticalSection(&g_cs);

   }

   return0;

}

voidmain()

{

   HANDLE hThread1 =CreateThread(NULL, 0, Func1, NULL, 0, NULL);

   HANDLE hThread2 =CreateThread(NULL, 0, Func2, NULL, 0, NULL);

   CloseHandle(hThread1);

   CloseHandle(hThread2);

   hMutex = CreateMutex(NULL,FALSE,NULL);

   //hEvent =CreateEvent(NULL, FALSE, TRUE,NULL);

   //InitializeCriticalSection(&g_cs);

   Sleep(4000);

   //DeleteCriticalSection(&g_cs);

}

1利用互斥对象实现线程同步

互斥对象属于内核对象,它能够确保线程拥有对单个资源的互斥访问权,互斥对象包含一个使用数量、线程ID和一个计数器。其中ID用于标识系统中哪个线程当前拥有互斥对象,计数器用于指明该线程拥有互斥对象的次数。

创建互斥对象使用函数CreateMutex,该函数可以创建或打开一个命名的或匿名的互斥对象,然后程序就可以利用该互斥对象完成线程间的同步。CreateMutex的声明如下:

HANDLE CreateMutex(LPSECURITY_ATTRIBUTES  lpMutexAttributes, BOOL bInitialOwner, LPCTSTRlpName)

该函数具有三个参数,

lpMutexAttributes指向SECURITY_ATTRIBUTES结构的指针,这里可以传递NULL,让该互斥对象使用默认的安全性。

bInitialOwner BOOL类型,指定互斥对象初始的拥有者,如果该值为真,则创建这个互斥对象的线程获得该对象的所有权,否则该线程将不获得该对象的所有权。

lpName 指定互斥对象的名称,如果该参数为NULL,则创建一个匿名的互斥对象。

如果调用成功,该函数将返回所创建的互斥对象的句柄。如果创建的是命名的互斥对象,并且在调用CreateMutex之前,该命名的互斥对象存在,那么该函数将返回已经存在的这个互斥对象的句柄,而这时调用GetLastError函数将返回ERROR_ALREADY_EXISTS.

函数ReleaseMutex释放指定对象的访问权,原型如下

BOOLReleaseMutex(HANDE hMutex);

线程必须主动请求该共享对象的使用权才有可能获得该所有权,这可以通过调用WaitFofSingleObject函数来实现,原型如下

DWORDWaitFofSingleObject(HANDE hHandle, DWORD dwMilliseconds);

hHandle 所请求的对象句柄,一旦互斥对象处于有信号状态,该函数就返回,否则一直等待。

dwMilliseconds     指定等待的时间间隔,以毫秒为单位,如果该参数为INFINITE,会一直等待。


思考以下问题

1在函数Fun1和Fun2中调用WaitForSingleObject和ReleaseMutex的位置能否放在while循环之外?

2main函数创建互斥对象时,第二参数指定为TRUE,即主线程获得互斥对象的所有权,为了保证子线程正常运行,应怎么办?

3如果main函数创建互斥对象后立即调用WaitForSingleObject,为了保证子线程正常运行,应怎么办?

为了保证应用程序只有一个实例运行,利用CreateMutex的返回值,如果返回一个有效的句柄,接着调用GetLastError函数,如果该函数返回ERROR_ALREADY_EXISTS,就表明已经创建了这个命名的互斥对象。代码如下:

void main()

{

   HANDLE hThread1 =CreateThread(NULL, 0, Func1, NULL, 0, NULL);

   HANDLE hThread2 =CreateThread(NULL, 0, Func2, NULL, 0, NULL);

   CloseHandle(hThread1);

   CloseHandle(hThread2);

   hMutex = CreateMutex(NULL, FALSE,"tickets");

   if(hMutex)

      if(ERROR_ALREADY_EXISTS == GetLastError())

      {

        cout<<"Only one instance can run"<<endl;

        return;

      }

Sleep(4000);

}

2事件对象

事件对象也属于内核对象,它包含以下三个成员:

使用计数

用于指明该事件是一个自动重置的事件还是人工重置的事件的布尔值

用于指明该事件处于已通知状态还是未通知状态的布尔值。

事件对象有两种不同的类型,人工重置的事件对象和自动重置的事件对象。当人工重置的事件对象得到通知时,等待该事件对象的所有线程均变为可调度线程,当自动重置的事件对象得到通知时,等待该事件对象的线程中只有一个线程变为可调度线程。

在程序中使用CreateEvent函数创建或打开一个匿名的或命名的事件对象,原型如下:

HANDLE CreateEvent(LPSECURITY_ATTRIBUTES   lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName);

lpEventAttributes:指向SECURITY_ATTRIBUTES的指针,这里可以传递NULL,则使用默认的安全性。

bManualReset,指定创建的是人工重置对象还是自动重置对象。

bInitialState,指定事件对象的初始状态。

lpName指定事件对象的名称,如果值为NULL,创建一个匿名的对象。

设置事件对象状态BOOL SetEvent(HANDLE  hEvent);

重置事件对象状态 BOOL ResetEvent(HANDLE  hEvent);

为了实现线程的同步,应该使用自动重置对象。

2关键段代码,也称临界区,工作在用户方式下,它是指一个小代码段,在代码能够执行前,他必须独占对某些资源的访问权。

相关函数

voidInitializeCriticalSection(LPCRITICAL_SECTION  lpCriticalSection);

参数lpCriticalSection作为返回值来用.

EnterCriticalSection(LPCRITICAL_SECTION  lpCriticalSection);

LeaveCriticalSection(LPCRITICAL_SECTION  lpCriticalSection);

DeleteCriticalSection(LPCRITICAL_SECTION  lpCriticalSection);

三种同步方式比较:

1互斥对象和事件对象都属于内核对象,利用内核对象进行线程同步时,速度较慢,但可以在多个进程中的各个线程 间进行同步。

2关键段代码工作在用户方式下,同步速度较快,但在使用关键段代码时,很容易进入死锁状态,因为在等待进入关键段代码时无法设定超时值。

 总结自孙鑫《vc++编程详解》

 


告别‘找不到dll’:在Windows上用VS2022和VSCode搞定libsndfile音频库的完整配置流程 本文详细介绍了在Windows系统下使用Visual Studio 2022和VSCode配置libsndfile音频库的完整流程,解决常见的'找不到dll'等问题。从环境准备、库文件获取到双平台的具体配置步骤,帮助开发者快速集成这一强大的音频处理工具,提升C++项目开发效率。 阅读详情

相关推荐

python 和 c++ 实现网络端口扫描器 含windows平台和Linux平台

网络端口扫描器 采用python c++两种语言开发。分别有windows平台和Linux平台版本。 介绍:输入端口号进行扫描,支持多线程,支持特定端口扫描或全端口扫描。

weixin_46703850的博客 989

C++多线程编程

C++多线程 1. 概念 1.1 概念 进程:一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。 线程:进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程

WLSTLA 844

多线程编程中的Windows条件变量与C++11同步对象

本文深入探讨了在Windows系统中条件变量的使用及特点,以及如何利用C++11提供的线程同步对象来编写跨平台的多线程程序。通过对比Linux条件变量,我们了解到Windows条件变量仅在特定版本后才得到支持,并且是user-mode对象。同时,文章也介绍了在多进程之间共享线程同步对象的技巧,并详细解释了C++11中std::mutex系列及std::lock_guard的使用方法和最佳实践。

weixin_36369848的博客 299

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

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

hanxiaoyong_的博客 2669

告别硬编码!用Aviator 5.3.3实现动态规则引擎,Spring Boot项目实战教程

本文详细介绍了如何使用Aviator 5.3.3在Spring Boot项目中实现动态规则引擎,告别硬编码。通过Maven依赖集成、规则模型设计、规则执行引擎实现及电商促销系统实战案例,展示了Aviator在动态规则配置中的高效应用,提升业务灵活性和开发效率。

weixin_30329623的博客 446

【中兴交换机MC-LAG配置】

​ 中兴mc-lag配置 主设备配置如下: Keepalive链路 interface smartgroup1023 //用作MC-LAG的Keepalive链路接口 switch attribute disable yes description For_Keepalived exit interface xgei-0/1/1/47 switch attribute disable yes description For_Keepalived exit interface

qq_31440733的博客 1万+

【C/C++】开启线程

本文讲解了C/C++如何开启线程,以及执行过程,最后结束线程的流程,提供了完整代码示例,以及周边必备的函数介绍

chrisTS90的专栏 3887

使用示波器通过串口抓取数据波形

当我们在软件上发送一个数据,需要在示波器上正确的显示发送数据的波形时,这个过程是需要按照软件上串口配置的参数对示波器进行调节的,本次使用的示波器(型号为RIGOL DS1102Z-E)外观如下图所示,本次对采集波形的调节主要用到以下几处按钮。具体是两条导线T+连接R+、T-连接R-,连接完毕后,打开XCOM软件,首先配置好参数后打开串口,如下所示,若在发送窗口发送数据在接收窗口可以实时显示到的话,证明串口的收发功能是正常的。1.CH1、CH2是示波器上的两个采集通道,本次波形采集使用的是CH1通道。

weixin_58061628的博客 1万+

简单了解C++线程库

在C++11之前,涉及到多线程问题,都是和平台相关的,比如windows和linux下各有自己的接口,这使得代码的可移植性比较差。C++11中最重要的特性就是对线程进行支持了,使得C++在并行编程时不需要依赖第三方库,而且在原子操作中还引入了原子类的概念。要使用标准库中的线程,必须包含< thread >头文件。return 0;另外,由于我这里没有传参,所以这是一个空线程,它不会启动的。除非进行移动赋值。

m0_74099572的博客 1545

支付宝支付(三):周期扣款实现注意细节

一、周期扣款实现说明 1、官方文档入口:https://opendocs.alipay.com/open/20190319114403226822/intro 2、根据官方文档说明,周期扣款有两种方式:先签约后代扣场景和支付后签约场景 3、周期扣款接入问题文档: a>https://opendocs.alipay.com/support/01rg24 b>https://opensupport.alipay.com/support/knowledge/50249/20160248753

新鲜雾霾的博客 5695

【CVPR2025 DEIM】超详细!手把手训练自己的数据集教学:从源码下载,配置虚拟环境,准备数据集、训练、验证、推理测试 ,实现0到1的完整教学过程。本文在win系统上训练,最强实时目标检测算法!

本文详细介绍了CVPR2025 DEIM目标检测模型的完整使用流程。内容包含:1)源码下载与虚拟环境配置;2)Visdrone2019数据集准备与配置文件修改;3)训练参数设置及Windows系统常见问题解决方案;4)模型验证、推理测试及热力图生成方法。特别针对Windows用户提供了虚拟环境配置指导,并详细说明了数据集路径设置、参数调整等关键步骤。通过本文的指导,小伙伴可以快速掌握DEIM模型的使用方法,用于学术论文研究和实验分析。

Ai缝合怪、助力小伙伴高效发论文 7627

C++和python多线程yolov8读取和predict和写入视频

codes见:支持C++和python模块的,共三个线程合作,每个线程独立工作,就像消费者和生产者。读取视频的线程是一个生产者,对视频帧做inference的线程是消费者,对视频帧做inference的线程会给出predict的结果,现在它是一个生产者,绘制和保存线程在视频帧上绘制矩形框,并且保存到视频中,它是一个消费者,所以第二个线程既是生产者也是消费者。要实现这些功能,需要线程安全的队列。Python标准库提供了一个线程安全的队列库Queue,是queue库内的一个类。

邹九的个人博客 1813

YOLOv11 热力图可视化全流程:从模型解释到科研论证,让检测结果“有理可看”

无论是科研中需要严谨的模型解释,还是工业里要高效的缺陷定位,这套方法都能让你在“模型黑箱”与“业务需求”之间架起一座可视化的桥梁。别再让模型决策“无据可依”——现在就动手生成你的第一幅热力图,让 YOLOv11 的每一次检测都“有理可看”,用可视化的力量推动你的 AI 研究与落地走向深入!某团队在论文中通过热力图对比,证明其改进的注意力模块可使模型对小目标的关注区域更精准,实验论证说服力提升 50%;工业质检场景下,热力图帮助工程师快速定位模型漏检缺陷的原因——原来是对某类缺陷的特征关注不足。

m0_71589036的博客 677

C++多线程编程简单实例

今天我给大家讲一讲C++中的多线程编程技术,C++本身并没有提供任何多线程机制,但是在windows下,我们可以调用SDK win32 api来编写多线程的程序,下面我就此简单的讲一下:   创建线程的函数     HANDLE CreateThread(      LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD

Mr. Feng 1100

Claude Code 完整详解(Anthropic 官方 AI 编程 Agent)

它是运行在终端(Terminal)的 AI 编程代理,不是普通 IDE 插件;你用自然语言发指令,它自主规划步骤、读写项目文件、执行系统命令、排查 Bug、处理 Git 工作流,是能真正动手干活的 AI 程序员。真正的AI 开发代理人,不止写代码,还能执行开发全流程超长全局上下文,大型项目理解碾压传统补全工具终端原生 + IDE 双接入,开发流程无割裂代码质量、可读性、工程规范性普遍偏高权限安全机制完善,修改前预览、可随时中断回滚。

wange6906的博客 3155

Sprd Android 13 备忘 OTA升级app没更新到目标版本,恢复出厂才生效修改这个值

【代码】Sprd Android 13 备忘 OTA升级app没更新到目标版本,恢复出厂才生效修改这个值。

m0_60898338的博客 679

c++多线程编程(一)

C++本身并没有提供任何多线程机制,但是在windows下,我们可以调用SDK win32 api来编写多线程的程序,下面就此简单的讲一下: 创建线程的函数 HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD SIZE_T dwStackSize, ...

weixin_30546189的博客 64

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

LEADTOOLS 使用自动识别管理器的多线程OCR- Windows C DLL

本教程介绍如何在 C/C++ Windows API 应用程序中使用 LEADTOOLS SDK 对 OCR 引擎进行多线程并行处理。

控件与插件之大全 1046

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【C++ windows多线程使CPU 100%】

用于windows 平台的CPU 100% 预警测试程序,c++实现

wvxvsuizhong的博客 2111

Statistics and Machine Learning Toolbox

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

C++ 多线程讲解及示例代码

C++本身并没有提供任何多线程机制,但是在windows下,我们可以调用SDK win32 api来编写多线程程序。 创建线程函数: HANDLE CreateThread(   LPSECURITY_ATTRIBUTESlpThreadAttributes,  //默认安全级别0   SIZE_T dwStackSize,    //堆栈大小默认(2M)   LPTHREAD_STAR

lixuemei504的专栏 1419

简单的多线程理解

C++本身并没有提供任何多线程机制,但是在windows下,我们可以调用SDK win32 api来编写多线程的程序,下面就此简单的讲一下: 创建线程的函数 HANDLE CreateThread(      LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD     SIZE_T dwStackSize,                    

ranjiewen的博客 379

c++编写HTTP API服务端/客户端最简单的库,没有之一

libhv是c++编写HTTP API 服务端/客户端最简单的库,没有之一。 具有以下特性: 跨平台(Windows, Linux, Mac); 支持RESTful; 支持application/json、application/x-www-form-urlencoded、multipart/form-data; 内置web service文件服务和indexof service目录服务;

HW的博客 4万+
上一篇: 动态链接库dll详解
下一篇: 华三面试小结
skilledprogrammer
博客等级 码龄19年 78粉丝 53原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值