- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
在Windows平台下创建多线程有两种方式,读者可以使用 CreateThread 函数,或者使用 beginthreadex 函数均可,两者虽然都可以用于创建多线程环境,但还是存在一些差异的,首先 CreateThread 函数它是 Win32 API 的一部分,而 _beginthreadex 是 C/C++ 运行库的一部分,在参数返回值类型方面, CreateThread 返回线程句柄,而 _beginthreadex 返回线程ID,当然这两者在使用上并没有太大的差异,但为了代码更加通用笔者推荐使用后者,因为后者与平台无关性更容易实现跨平台需求.
CreateThread 函数是 Windows API 提供的用于创建线程的函数。它接受一些参数,如线程的入口函数、线程的堆栈大小等,可以创建一个新的线程并返回线程句柄。开发者可以使用该句柄控制该线程的运行状态。需要注意,在使用 CreateThread 创建线程时,线程入口函数的返回值是线程的退出码,而不是线程执行的结果值.
CreateThread 函数原型如下:
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
参数说明:
SECURITY_ATTRIBUTES
结构体的指针,指定线程安全描述符和访问权限。通常设为NULL,表示使用默认值。 dwStackSize
为0,则使用默认的堆栈大小。(注:在32位程序下,该值的默认大小为1MB;在64位程序下,该值的默认大小为4MB) DWORD
变量的指针,表示返回的线程ID号。可以为NULL。 CreateThread 函数将创建一个新的线程,并返回线程句柄。开发者可以使用该句柄控制该线程的运行状态,如挂起、恢复、终止等。线程创建成功后,执行线程函数进行相应的业务处理。需要注意的是,在使用 CreateThread 创建线程时,线程入口函数的返回值是线程的退出码,而不是线程执行的结果值.
#include <windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI Func(LPVOID lpParamter)
{
for (int x = 0; x < 10; x++)
{
cout << "thread function" << endl;
Sleep(200);
}
return 0;
}
int main(int argc,char * argv[])
{
HANDLE hThread = CreateThread(NULL, 0, Func, NULL, 0, NULL);
CloseHandle(hThread);
for (int x = 0; x < 10; x++)
{
cout << "main thread" << endl;
Sleep(400);
}
system("pause");
return 0;
}
如上所示代码中我们在线程函数 Func() 内没有进行任何的加锁操作,那么也就会出现资源的争夺现象,这些会被抢夺的资源就被称为是临界资源,我们可以通过设置临界锁来实现同一时刻内保持一个线程操作资源.
EnterCriticalSection 是Windows API提供的线程同步函数之一,用于进入一个临界区并且锁定该区域,以确保同一时间只有一个线程访问临界区代码.
EnterCriticalSection函数的函数原型如下:
void EnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
参数说明:
EnterCriticalSection 函数将等待,直到指定的临界区对象可用并且已经锁定,然后,当前线程将进入临界区。临界区中的代码将在当前线程完成之前,不允许被任何其他线程执行。当线程完成临界区的工作时,应该调用 LeaveCriticalSection 函数释放临界区。否则,其他线程将无法进入临界区,导致死锁.
EnterCriticalSection 函数是比较底层的线程同步函数,需要开发者自行创建临界区,维护临界区的状态并进行加锁解锁的操作,使用时需要注意对临界区中的操作进行适当的封装和处理。同时, EnterCriticalSection 函数也是比较高效的线程同步方式,对于需要频繁访问临界资源的场景,可以通过使用临界区来提高程序的性能.
#include <Windows.h>
#include <iostream>
int Global_One = 0;
// 全局定义临界区对象
CRITICAL_SECTION g_cs;
// 定义一个线程函数
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
// 加锁防止线程数据冲突
EnterCriticalSection(&g_cs);
for (int x = 0; x < 10; x++)
{
Global_One++;
Sleep(1);
}
// 执行完修改以后,需要释放锁
LeaveCriticalSection(&g_cs);
return 0;
}
int main(int argc, char * argv[])
{
// 初始化临界区
InitializeCriticalSection(&g_cs);
HANDLE hThread[10] = { 0 };
for (int x = 0; x < 10; x++)
{
// 循环创建线程
hThread[x] = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
}
// 等待多个线程执行结束
WaitForMultipleObjects(10, hThread, TRUE, INFINITE);
// 最后循环释放资源
for (int x = 0; x < 10; x++)
{
CloseHandle(hThread[x]);
}
printf("全局变量值: %d \n", Global_One);
// 释放锁
DeleteCriticalSection(&g_cs);
system("pause");
return 0;
}
BeginThreadex 是 C/C++ 运行库提供的用于创建线程的函数。它也接受一些参数,如线程的入口函数、线程的堆栈大小等,与 CreateThread 不同的是, _beginthreadex 函数返回的是线程的ID,而不是线程句柄。开发者可以使用该 ID 在运行时控制该线程的运行状态。此外, _beginthreadex 函数通常与 _endthreadex 配对使用,供线程退出时使用.
beginthreadex 函数的函数原型如下:
uintptr_t _beginthreadex(
void* security,
unsigned stack_size,
unsigned(__stdcall* start_address)(void*),
void* arglist,
unsigned initflag,
unsigned* thrdaddr
);
参数说明:
Windows
安全机制相关,用于指定线程的安全属性,一般填NULL即可。 stack_size
为0,则使用默认的堆栈大小。 CREATE_SUSPENDED
表示启动线程后暂停运行。 unsigned
变量的指针,表示返回的线程ID号。可以为NULL。 与 CreateThread 相比, _beginthreadex 函数返回线程ID而非线程句柄,使用时需要注意区分。与 CreateThread 不同的是, _beginthreadex 函数接受传递给线程函数的参数放在 arglist 中,方便传递多个参数。线程使用完需要调用 _endthreadex 函数来关闭线程。当使用了 _beginthreadex 创建的线程退出时,会调用 _endthreadex 来结束线程,这里的返回值会被当做线程的退出码.
#include <windows.h>
#include <iostream>
#include <process.h>
using namespace std;
unsigned WINAPI Func(void *arg)
{
for (int x = 0; x < 10; x++)
{
cout << "thread function" << endl;
Sleep(200);
}
return 0;
}
int main(int argc, char * argv[])
{
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, Func, NULL, 0, NULL);
CloseHandle(hThread);
for (int x = 0; x < 10; x++)
{
cout << "main thread" << endl;
Sleep(400);
}
system("pause");
return 0;
}
由于 CreateThread() 函数是 Windows 提供的API接口,在 C/C++ 语言另有一个创建线程的函数 _beginthreadex() 该函数在创建新线程时会分配并初始化一个 _tiddata 块,这个块用来存放一些需要线程独享的数据,从而保证了线程资源不会发生冲突的情况,代码只需要稍微在上面基础上改进即可.
当然该函数同样需要设置线程临界区而设置方式与 CreateThread 中所展示的完全一致.
#include <stdio.h>
#include <process.h>
#include <windows.h>
// 全局资源
long g_nNum = 0;
// 子线程个数
const int THREAD_NUM = 10;
CRITICAL_SECTION g_csThreadCode;
unsigned int __stdcall ThreadFunction(void *ptr)
{
int nThreadNum = *(int *)ptr;
// 进入线程锁
EnterCriticalSection(&g_csThreadCode);
g_nNum++;
printf("线程编号: %d --> 全局资源值: %d --> 子线程ID: %d \n", nThreadNum, g_nNum, GetCurrentThreadId());
// 离开线程锁
LeaveCriticalSection(&g_csThreadCode);
return 0;
}
int main(int argc,char * argv[])
{
unsigned int ThreadCount = 0;
HANDLE handle[THREAD_NUM];
InitializeCriticalSection(&g_csThreadCode);
for (int each = 0; each < THREAD_NUM; each++)
{
handle[each] = (HANDLE)_beginthreadex(NULL, 0, ThreadFunction, &each, 0, &ThreadCount);
printf("线程ID: %d \n", ThreadCount);
}
WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);
DeleteCriticalSection(&g_csThreadCode);
system("pause");
return 0;
}
总的来说, _beginthreadex 比 CreateThread 更加高级,封装了许多细节,使用起来更方便,特别是对于传递多个参数的情况下,可以更简单地传参.
本文作者: 王瑞 本文链接: https://www.lyshark.com/post/922df2e6.html 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处! 。
最后此篇关于9.1运用API创建多线程的文章就讲到这里了,如果你想了解更多关于9.1运用API创建多线程的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我将 Bootstrap 与 css 和 java 脚本结合使用。在不影响前端代码的情况下,我真的很难在css中绘制这个背景。在许多问题中,人们将宽度和高度设置为 0%。但是由于我的导航栏,我不能使用
我正在用 c 编写一个程序来读取文件的内容。代码如下: #include void main() { char line[90]; while(scanf("%79[^\
我想使用 javascript 获取矩阵数组的所有对 Angular 线。假设输入输出如下: input = [ [1,2,3], [4,5,6], [7,8,9], ] output =
可以用pdfmake绘制lines,circles和other shapes吗?如果是,是否有documentation或样本?我想用jsPDF替换pdfmake。 最佳答案 是的,有可能。 pdfm
我有一个小svg小部件,其目的是显示角度列表(参见图片)。 现在,角度是线元素,仅具有笔触,没有填充。但是现在我想使用一种“内部填充”颜色和一种“笔触/边框”颜色。我猜想line元素不能解决这个问题,
我正在为带有三角对象的 3D 场景编写一个非常基本的光线转换器,一切都工作正常,直到我决定尝试从场景原点 (0/0/0) 以外的点转换光线。 但是,当我将光线原点更改为 (0/1/0) 时,相交测试突
这个问题已经有答案了: Why do people write "#!/usr/bin/env python" on the first line of a Python script? (22 个回
如何使用大约 50 个星号 * 并使用 for 循环绘制一条水平线?当我尝试这样做时,结果是垂直(而不是水平)列出 50 个星号。 public void drawAstline() { f
这是一个让球以对角线方式下降的 UI,但球保持静止;线程似乎无法正常工作。你能告诉我如何让球移动吗? 请下载一个球并更改目录,以便程序可以找到您的球的分配位置。没有必要下载足球场,但如果您愿意,也可以
我在我的一个项目中使用 Jmeter 和 Ant,当我们生成报告时,它会在报告中显示 URL、#Samples、失败、成功率、平均时间、最短时间、最长时间。 我也想在报告中包含 90% 的时间线。 现
我有一个不寻常的问题,希望有人能帮助我。我想用 Canvas (android) 画一条 Swing 或波浪线,但我不知道该怎么做。它将成为蝌蚪的尾部,所以理想情况下我希望它的形状更像三角形,一端更大
这个问题已经有答案了: Checking Collision of Shapes with JavaFX (1 个回答) 已关闭 8 年前。 我正在使用 JavaFx 8 库。 我的任务很简单:我想检
如何按编号的百分比拆分文件。行数? 假设我想将我的文件分成 3 个部分(60%/20%/20% 部分),我可以手动执行此操作,-_-: $ wc -l brown.txt 57339 brown.tx
我正在努力实现这样的目标: 但这就是我设法做到的。 你能帮我实现预期的结果吗? 更新: 如果我删除 bootstrap.css 依赖项,问题就会消失。我怎样才能让它与 Bootstrap 一起工作?
我目前正在构建一个网站,但遇到了 transform: scale 的问题。我有一个按钮,当用户将鼠标悬停在它上面时,会发生两件事: 背景以对 Angular 线“扫过” 按钮标签颜色改变 按钮稍微变
我需要使用直线和仿射变换绘制大量数据点的图形(缩放图形以适合 View )。 目前,我正在使用 NSBezierPath,但我认为它效率很低(因为点在绘制之前被复制到贝塞尔路径)。通过将我的数据切割成
我正在使用基于 SVM 分类的 HOG 特征检测器。我可以成功提取车牌,但提取的车牌除了车牌号外还有一些不必要的像素/线。我的图像处理流程如下: 在灰度图像上应用 HOG 检测器 裁剪检测到的区域 调
我有以下图片: 我想填充它的轮廓(即我想在这张图片中填充线条)。 我尝试了形态学闭合,但使用大小为 3x3 的矩形内核和 10 迭代并没有填满整个边界。我还尝试了一个 21x21 内核和 1 迭代,但
我必须找到一种算法,可以找到两组数组之间的交集总数,而其中一个数组已排序。 举个例子,我们有这两个数组,我们向相应的数字画直线。 这两个数组为我们提供了总共 7 个交集。 有什么样的算法可以帮助我解决
简单地说 - 我想使用透视投影从近裁剪平面绘制一条射线/线到远裁剪平面。我有我认为是使用各种 OpenGL/图形编程指南中描述的方法通过单击鼠标生成的正确标准化的世界坐标。 我遇到的问题是我的光线似乎
我是一名优秀的程序员,十分优秀!