C++ 多线程学习总结
本文主要参考以下链接,感谢前辈的分享。
秒杀多线程 多线程总结
先来一个简单的例子,展示如何创建一个线程
#include <windows.h>
#include <process.h>
#include <iostream>
using namespace std;
unsigned Counter;unsigned __stdcall SecondThreadFunc(PVOID pArguments)
{printf("In second thread...\n");while (Counter < 1000000)Counter++;printf("done\n");_endthreadex(0);//如果把 printf("done\n");放在此段代码之后,则不会执行return 0;
}int main()
{HANDLE hThread;unsigned threadID;// Create the second thread. hThread = (HANDLE)_beginthreadex(NULL, 0, &SecondThreadFunc, NULL, 0, &threadID);//创建线程函数WaitForSingleObject(hThread, INFINITE);//注意这个函数的使用printf("Counter should be 1000000; it is-> %d\n", Counter);cout << threadID << endl;// Destroy the thread object. CloseHandle(hThread);//个人感觉仅仅关闭了句柄,并没有关闭线程资源,也即线程还在跑system("pause");return 0;
}
WaitForSingleObject 函数介绍
WaitForSingleObject(hThread, INFINITE); 等待hThread这个线程发出信号,才会执行接下来的代码。INFINITE表示无期限等待,直到hThread线程发出信号。
WaitForSingleObject(hThread, 10); 表示等待10ms,10ms内发出信号,则返回WAIT_OBJECT_0,超过时间则返回WAIT_TIMEOUT。如果该函数失败,返回WAIT_FAILED。
可以通过下面的代码来判断:
DWORD dw = WaitForSingleObject(hProcess, 5000); //等待一个进程结束
switch (dw)
{
case WAIT_OBJECT_0:
// hProcess所代表的进程在5秒内结束
break;
case WAIT_TIMEOUT:
// 等待时间超过5秒
break;
case WAIT_FAILED:
// 函数调用失败,比如传递了一个无效的句柄
break;
}
还可以使用WaitForMulitpleObjects函数来等待多个内核对象变为已通知状态:
DWORD WaitForMultipleObjects(
DWORD dwCount, //等待的内核对象个数
CONST HANDLE* phObjects, //一个存放被等待的内核对象句柄的数组
BOOL bWaitAll, //是否等到所有内核对象为已通知状态后才返回
DWORD dwMilliseconds); //等待时间
该函数的第一个参数指明等待的内核对象的个数,可以是0到MAXIMUM_WAIT_OBJECTS(64)中的一个值。phObjects参数是一个存放等待的内核对象句柄的数组。bWaitAll参数如果为TRUE,则只有当等待的所有内核对象为已通知状态时函数才返回,如果为FALSE,则只要一个内核对象为已通知状态,则该函数返回。第四个参数和WaitForSingleObject中的dwMilliseconds参数类似。
临界区和事件 解决线程同步和互斥问题 的例子
#include<iostream>
#include <process.h>
#include <windows.h>
using namespace std;long g_nNum;
unsigned int __stdcall Fun(PVOID pPM);
const int THREAD_NUM = 10;
//事件与关键段
HANDLE g_hThreadEvent;
CRITICAL_SECTION g_csThreadCode;
int main()
{cout << " 经典线程同步 事件Event\n" << endl;//初始化事件和关键段 自动置位,初始无触发的匿名事件 g_hThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);InitializeCriticalSection(&g_csThreadCode);HANDLE handle[THREAD_NUM];g_nNum = 0;int i = 0;while (i < THREAD_NUM){handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL);WaitForSingleObject(g_hThreadEvent, INFINITE); //等待事件被触发 i++;}WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);//销毁事件和关键段 CloseHandle(g_hThreadEvent);DeleteCriticalSection(&g_csThreadCode);system("pause");return 0;
}
unsigned int __stdcall Fun(PVOID pPM)
{int nThreadNum = *(int *)pPM;SetEvent(g_hThreadEvent); //触发事件 Sleep(50);//some work should to do EnterCriticalSection(&g_csThreadCode);g_nNum++;Sleep(0);//some work should to do cout << "线程编号为:" << nThreadNum << "全局资源为:" << g_nNum << endl;LeaveCriticalSection(&g_csThreadCode);return 0;
}
关键段CRITICAL_SECTION一共就六个函数,使用很是方便。如下所示为常用的四个函数
函数功能:初始化
函数原型:void InitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
函数说明:定义关键段变量后必须先初始化。
函数功能:销毁
函数原型:void DeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
函数说明:用完之后记得销毁。
函数功能:进入关键区域
函数原型:void EnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
函数说明:系统保证各线程互斥的进入关键区域。
函数功能:离开关关键区域
函数原型:void LeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
事件Event实际上是个内核对象,它的使用非常方便。下面列出一些常用的函数。(CreateEvent,SetEvent,ResetEvent)
CreateEvent
函数功能:创建事件
函数原型:
HANDLECreateEvent(
LPSECURITY_ATTRIBUTESlpEventAttributes,
BOOLbManualReset,
BOOLbInitialState,
LPCTSTRlpName
);
函数说明:
第一个参数表示安全控制,一般直接传入NULL。
第二个参数确定事件是手动置位还是自动置位,传入TRUE表示手动置位,传入FALSE表示自动置位。如果为自动置位,则对该事件调用WaitForSingleObject()后会自动调用ResetEvent()使事件变成未触发状态。打个小小比方,手动置位事件相当于教室门,教室门一旦打开(被触发),所以有人都可以进入直到老师去关上教室门(事件变成未触发)。自动置位事件就相当于医院里拍X光的房间门,门打开后只能进入一个人,这个人进去后会将门关上,其它人不能进入除非门重新被打开(事件重新被触发)。
第三个参数表示事件的初始状态,传入TRUR表示已触发。
第四个参数表示事件的名称,传入NULL表示匿名事件。
SetEvent
函数功能:触发事件
函数原型:BOOLSetEvent(HANDLEhEvent);
函数说明:每次触发后,必有一个或多个处于等待状态下的线程变成可调度状态。
ResetEvent
函数功能:将事件设为末触发
函数原型:BOOLResetEvent(HANDLEhEvent);
最后一个事件的清理与销毁
由于事件是内核对象,因此使用CloseHandle()就可以完成清理与销毁了。
C++ 多线程学习总结相关推荐
- Java多线程学习处理高并发问题
在程序的应用程序中,用户或请求的数量达到一定数量,并且无法避免并发请求.由于对接口的每次调用都必须在返回时终止,因此,如果接口的业务相对复杂,则可能会有多个用户.调用接口时,该用户将冻结. 以下内容将 ...
- C#多线程学习(四) 多线程的自动管理(线程池) (转载系列)——继续搜索引擎研究...
在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应 这一般使用ThreadPo ...
- 艾伟:C#多线程学习(六) 互斥对象
本系列文章导航 C#多线程学习(一) 多线程的相关概念 C#多线程学习(二) 如何操纵一个线程 C#多线程学习(三) 生产者和消费者 C#多线程学习(四) 多线程的自动管理(线程池) C#多线程学习( ...
- C# 多线程学习总结
C#多线程学习(一) 多线程的相关概念 什么是进程? 当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程? 线程是 ...
- C#多线程学习(二) 如何操纵一个线程
C#多线程学习(二) 如何操纵一个线程 原文链接:http://kb.cnblogs.com/page/42529/ [1] C#多线程学习(二) 如何操纵一个线程 [2] C#多线程学习(二) 如何 ...
- 多线程学习-基础(四)常用函数说明:sleep-join-yield
一.常用函数的使用 (1)Thread.sleep(long millis):在指定的毫秒内让当前正在执行的线程休眠(暂停执行),休眠时不会释放当前所持有的对象的锁. (2)join():主线程等待子 ...
- C#多线程学习之(五)使用定时器进行多线程的自动管理
本文实例讲述了C#多线程学习之使用定时器进行多线程的自动管理.分享给大家供大家参考.具体分析如下: Timer类:设置一个定时器,定时执行用户指定的函数. 定时器启动后,系统将自动建立一个新的线程,执 ...
- java多线程学习-java.util.concurrent详解
http://janeky.iteye.com/category/124727 java多线程学习-java.util.concurrent详解(一) Latch/Barrier 博客分类: java ...
- C#多线程学习(三) 生产者和消费者
C#多线程学习(三) 生产者和消费者 原文链接:http://kb.cnblogs.com/page/42530/ 本系列文章导航 C#多线程学习(一) 多线程的相关概念 C#多线程学习(二) 如何操 ...
- C#多线程学习(五) 多线程的自动管理(定时器) (转载系列)——继续搜索引擎研究...
Timer类:设置一个定时器,定时执行用户指定的函数. 定时器启动后,系统将自动建立一个新的线程,执行用户指定的函数. 初始化一个Timer对象: Timer timer ...
最新文章
- 现金奖励+实习offer!数据库大赛来了
- 不愧是你!Python 之父退休太无聊,进微软搞开源!
- vc采集网页内frame框架下所有元素(不指定具体table/form)
- python爬虫的应用-python网络爬虫应用实战
- convex function
- EJS学习(四)之语法规则下
- wxWidgets:wxCheckBox类用法
- 用正则表达式捕获标识符——随便说
- error: style attribute '@android:attr/windowEnterAnimation' not found
- iOS菜鸟之AFN的二次封装
- ESP32开发 2.添加.c.h并修改CMakeLists,来定制自己的工程
- [Python] L1-026. I Love GPLT-PAT团体程序设计天梯赛GPLT
- Python不能做游戏?游戏实战之-----《ink spill》(附游戏完整源码)
- 华为路由器支持ftp服务器,华为路由器FTP配置详解
- SpringCloud面试题及答案(2021年SpringCloud面试题大全带答案)
- ROS Launch使用总结
- 3-8 如何使用图片 CDN 优化图片
- 论文笔记-Understanding Convolution for Semantic Segmentation
- Day16:数据仓库设计
- Ajax提交与submit提交对比