多线程例子_InterlockedExchangeAdd

本文通过一个具体的多线程编程示例,探讨了竞态条件如何导致程序中的潜在风险,并介绍了InterlockedExchangeAdd函数作为解决方案来确保线程安全。

参考《windows核心编程》(第5版)

有问题的代码

#include <windows.h>
#include <iostream>

using namespace std;

long g_x = 0;

DWORD WINAPI ThreadFunc(LPVOID);

#define MaxCount 20

int main( void )
{
	DWORD threadId;
	HANDLE threadHandle[MaxCount];
	for (int i=0; i<MaxCount;++i)
	{
		threadHandle[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, &threadId);
	}

	Sleep(100);
	for (int i=0; i<MaxCount;++i)
	{
		CloseHandle(threadHandle[i]);
	}
	
	cout <<g_x<<endl;
	system("pause");
	return 0;
}


DWORD WINAPI ThreadFunc( LPVOID lpParam )
{
	g_x++;
	//InterlockedExchangeAdd(&g_x, 1);
	return TRUE; 
}
潜在风险

g_x++的汇编代码如下

mov         eax,dword ptr [g_x (417148h)] 
add         eax,1 
mov         dword ptr [g_x (417148h)],eax
在多线程环境下可能这样执行

1  mov         eax,dword ptr [g_x (417148h)] 
2  add         eax,1 

3  mov         eax,dword ptr [g_x (417148h)] 
4  add         eax,1 
5  mov         dword ptr [g_x (417148h)],eax

设g_x为1

在A线程中

1句时eax为1

2句时eax为2

到3句时 切换到B线程

在另一线程中

3句时eax为1

4句时eax为2

5句时g_x为2

当切换到A线程中时,继续执行

mov dword ptr[g_x(417147h)],eax

A线程中的eax为2

则g_x为2

原打算为3


解决方法

#include <windows.h>
#include <iostream>

using namespace std;

long g_x = 0;

DWORD WINAPI ThreadFunc(LPVOID);

#define MaxCount 20

int main( void )
{
	DWORD threadId;
	HANDLE threadHandle[MaxCount];
	for (int i=0; i<MaxCount;++i)
	{
		threadHandle[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, &threadId);
	}

	Sleep(100);
	for (int i=0; i<MaxCount;++i)
	{
		CloseHandle(threadHandle[i]);
	}
	
	cout <<g_x<<endl;
	system("pause");
	return 0;
}


DWORD WINAPI ThreadFunc( LPVOID lpParam )
{
	//g_x++;
	InterlockedExchangeAdd(&g_x, 1);
	return TRUE; 
}

InterlockedExchangeAdd函数原型为

LONG __cdecl InterlockedExchangeAdd(
  _Inout_  LONG volatile *Addend,
  _In_     LONG Value
);
参数

Added  变量的地址

Value  增量值

此函数保证递增值操作以原子方式进行。注意,我们必须保证传给此函数的变量地址是经过对齐的,否则此函数可能会失败。(可以使用C函数_aligned_malloc函数)。





<think>好的,用户遇到了一个链接错误LNK2019,具体是关于无法解析的外部符号cv::_interlockedExchangeAdd。这个错误通常发生在编译时找不到对应的函数实现。让我仔细分析一下可能的原因和解决方法。 首先,错误信息显示这个符号是在OpenCV的Mat::release函数中被引用的。这说明问题可能出在OpenCV库的链接上。用户的项目LXCameraCpp在链接阶段无法找到这个函数的实现,导致链接失败。 接下来,我需要考虑可能的原因。常见的原因包括: 1. **OpenCV库版本不匹配**:用户可能使用的OpenCV库版本与代码编译时使用的版本不一致。例如,如果代码是用较新版本的OpenCV编译的,而链接的是旧版本的库,可能会出现符号缺失的问题。特别是_interlockedExchangeAdd这个函数可能与多线程或原子操作相关,不同版本的实现可能有差异。 2. **库文件未正确链接**:项目配置中可能没有正确添加OpenCV的库文件,或者库文件的路径设置错误。需要检查链接器设置中的附加依赖项,确保所有必要的OpenCV库(如opencv_core.lib等)都被包含,并且路径正确。 3. **运行时库冲突**:项目的运行时库设置(如MDd vs MTd)可能与OpenCV库使用的设置不匹配。这会导致链接器找不到对应的符号,因为不同运行时库的编译选项不兼容。 4. **OpenCV配置错误**:如果用户自行编译了OpenCV,可能在编译过程中某些选项没有正确启用,导致生成的库文件缺少某些函数。需要确认编译OpenCV时的配置是否正确,特别是与多线程相关的选项。 接下来,针对这些可能的原因,逐步提供解决方案: **第一步:检查OpenCV版本一致性** 用户应确认项目中使用的OpenCV头文件和链接的库文件版本是否一致。如果最近升级了OpenCV版本,可能需要重新编译项目,并清理之前的构建缓存,确保没有旧版本残留。 **第二步:验证库文件链接设置** 在项目属性中,检查链接器的附加依赖项,确保所有必需的OpenCV库都被正确添加。例如,opencv_core.lib、opencv_imgproc.lib等。同时,检查库目录路径是否正确指向当前使用的OpenCV版本。 **第三步:检查运行时库设置** 在项目属性 -> C/C++ -> 代码生成 -> 运行时库,确认与OpenCV库使用的设置一致。例如,如果OpenCV是使用MDd(多线程调试DLL)编译的,项目也应设置为MDd,否则会出现不匹配。 **第四步:重新编译OpenCV** 如果用户是自行编译OpenCV,建议使用CMake重新生成解决方案,并确保勾选了BUILD_SHARED_LIBS选项(如果需要动态库),同时检查是否有与线程相关的选项被禁用。编译完成后,更新项目中的库路径指向新编译的库文件。 **第五步:检查环境变量和路径** 确保系统的PATH环境变量包含OpenCV的二进制目录(如bin文件夹),这样在运行时可以找到对应的DLL文件。虽然这主要影响运行时错误,但有时链接阶段也可能涉及动态库的查找。 **第六步:查看OpenCV社区或文档** 搜索错误信息,查看OpenCV的GitHub Issues或论坛是否有类似问题。可能有其他开发者遇到相同问题,并提供了解决方案,比如需要添加特定的预处理器定义或链接其他库。 最后,如果上述步骤仍未解决问题,建议用户提供更多关于项目配置的细节,如使用的OpenCV版本、编译器版本、构建系统(如VS版本)等,以便进一步排查。</think>这个错误属于链接错误,通常是由于缺少库文件或符号未正确链接导致的。以下是逐步分析和解决方案: --- ### **错误分析** - **错误代码**: LNK2019 - **说明**: 链接器无法找到符号 `cv::_interlockedExchangeAdd` 的实现。该符号在 `cv::Mat::release()` 中被引用。 - **根本原因**: 项目依赖的 **OpenCV库** 未正确链接,或库版本与代码不兼容(常见于多线程/原子操作相关的符号冲突)。 --- ### **解决步骤** #### **1. 检查OpenCV库版本** - **问题**: 若项目使用的OpenCV版本(如4.x)与编译时链接的库版本(如3.x)不一致,会导致符号不匹配。 - **操作**: 1. 确认安装的OpenCV版本(如通过`OpenCVConfig.cmake`或头文件`opencv2/core/version.hpp`)。 2. 确保项目配置中链接的库文件(如`opencv_core.lib`)与版本完全一致。 #### **2. 验证库文件路径** - **问题**: 链接器未找到OpenCV库文件。 - **操作**: 1. 在项目属性中检查 **附加库目录**(`Linker > General > Additional Library Directories`),确保路径指向正确的OpenCV库文件夹(如`H:\OpenCV\build\x64\vc15\lib`)。 2. 在 **附加依赖项**(`Linker > Input > Additional Dependencies`)中添加所需的OpenCV库文件(如`opencv_core455d.lib`,注意`d`表示调试版本)。 #### **3. 检查运行时库一致性** - **问题**: OpenCV库的运行时库(如`MDd`)与项目设置(如`MTd`)冲突。 - **操作**: 1. 右键项目 → **属性** → **C/C++** → **代码生成** → **运行时库**,确保与OpenCV库的编译选项一致(通常OpenCV默认使用`MDd`)。 2. 若需静态链接,需重新编译OpenCV并指定`/MT`或`/MTd`。 #### **4. 重新生成OpenCV库** - **问题**: 若自行编译OpenCV时配置错误(如未启用某些模块),可能导致符号缺失。 - **操作**: 1. 使用CMake重新配置OpenCV,勾选 `BUILD_SHARED_LIBS`(动态库)或取消勾选(静态库)。 2. 编译后更新项目中的库路径和依赖项。 #### **5. 检查环境变量** - **问题**: 系统未找到OpenCV的DLL文件(仅影响运行时,但需提前检查)。 - **操作**: 将OpenCV的`bin`目录(如`H:\OpenCV\build\x64\vc15\bin`)添加到系统环境变量`PATH`中。 #### **6. 代码兼容性检查** - **问题**: 代码中使用了不兼容的OpenCV API。 - **操作**: 1. 检查是否在代码中显式调用了`_interlockedExchangeAdd`,若有,改为标准原子操作(如C++11的`std::atomic`)。 2. 更新OpenCV到最新稳定版,避免已知的符号冲突问题。 --- ### **示例配置(VS2019)** 1. **包含目录**: ``` H:\OpenCV\build\include ``` 2. **库目录**: ``` H:\OpenCV\build\x64\vc15\lib ``` 3. **附加依赖项**: ``` opencv_core455d.lib opencv_imgproc455d.lib ...(其他所需模块) ``` --- ### **附加说明** - 若仍报错,尝试 **清理解决方案** 并重新生成。 - 参考OpenCV官方文档:[安装指南](https://docs.opencv.org/master/d3/d52/tutorial_windows_install.html)。 - 若使用预编译二进制包,确保选择与编译器匹配的版本(如VC14对应VS2015,VC16对应VS2019)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值