openCV、C++ 并发、windows
Posted
技术标签:
【中文标题】openCV、C++ 并发、windows【英文标题】:openCV, C++ concurrency, windows 【发布时间】:2014-02-20 13:43:38 【问题描述】:我们正在构建一个程序,该程序具有来自客户端的服务器流式视频。我们在 Visual Studio 中使用 C++。在调试模式下运行会消除所有奇怪的症状。
OBS:在发行版中运行,但使用 /0d 进行优化仍然会出现症状。
症状:调用 imshow("blabla", image);在服务器中,我们收到以下错误:“newCVS2.exe 中 0x54F26AF8 (opencv_highgui248d.dll) 处的未处理异常:0xC0000005:访问冲突读取位置 0x69577265。” 但是,如果我们执行 imwrite("example.jpg", otherimage);在我们没有收到此错误之前。 image 和 otherimage 是不同的图像。我们已经尝试单步执行代码,我所知道的没有发生奇怪的跳转。
在下面的代码中搜索 imwrite("test.jpg",tmp3) 使用下面的代码我们会得到错误,如果 imwrite 未注释我们不会。我包含了所有代码以供参考。
OBS:imwrite 解决了它不是原因的问题! 提前致谢,感谢任何 cmets。
代码示例:
// newCVS2.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <process.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#pragma comment (lib, "Ws2_32.lib")
using namespace std;
using namespace cv;
void streamServer(void* arg);
void quit(string msg, int retval);
int connect();
//HANDLE hMutex1;
Mat frame;
Mat img;
SOCKET ListenSocket;
SOCKET ClientSocket;
WSADATA wsaData;
int iResult;
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
int is_data_ready = 0;
HANDLE hMutex1 = CreateMutex( NULL, FALSE, NULL );
HANDLE syncMutex = CreateMutex( NULL, FALSE, NULL );
void streamServer(void* arg)
int imgSize = img.total()*img.elemSize();
char* sockData = new char[imgSize];
int bytes=0;
int errorMsg = connect();
if(errorMsg != 0)
cout << "error on: " << errorMsg;
SYSTEMTIME before;
SYSTEMTIME after;
// Receive until the peer shuts down the connection
memset(sockData, 0x0, sizeof(sockData));
do
GetSystemTime(&before);
for(int i = 0; i < imgSize; i += iResult)
iResult = recv(ClientSocket, sockData + i, imgSize - i, 0);
if(iResult == -1)
printf("resv failed");
GetSystemTime(&after);
cout << (((after.wSecond * 1000) + after.wMilliseconds) - ((before.wSecond * 1000 ) + before.wMilliseconds)) << " time for recv \n";
//int ptr = 0;
GetSystemTime(&before);
WaitForSingleObject( hMutex1, INFINITE );
for(int i = 0; i < img.rows; i++)
//row = sockData.part(
for(int j = 0; j < img.cols; j++)
(img.row(i)).col(j) = (uchar)sockData[((img.cols)*i)+j];
//img.at<cv::Vec3b>(i,j) = cv::Vec3b((uchar)sockData[ptr+ 0],(uchar)sockData[ptr+1],(uchar)sockData[ptr+2]);
//ptr = ptr + 3;
cout << img.rows << " number of rows ";
GetSystemTime(&after);
is_data_ready = 1;
memset(sockData, 0x0, sizeof(sockData));
ReleaseMutex( hMutex1 );
cout << (((after.wSecond * 1000) + after.wMilliseconds) - ((before.wSecond * 1000 ) + before.wMilliseconds)) << " time for annoying shit \n";
if (iResult > 0)
printf("Bytes received: %d\n", iResult);
//Close the connection
else if (iResult == 0)
printf("Connection closing...\n");
//Fail during connection
else
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
while (iResult > 0);
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR)
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
// cleanup
closesocket(ClientSocket);
WSACleanup();
int main()
int width, height;
width = 640;
height = 480;
img = Mat::zeros( height,width, CV_8UC1);
is_data_ready = 0; // not needed
_beginthread( streamServer, 0, NULL );
//needed to make sure that server does not close
while(true)
WaitForSingleObject( hMutex1, INFINITE );
if(is_data_ready)
cout << img.rows << " number rows before show \n";
cout << img.empty() << " empty? \n";
WaitForSingleObject( syncMutex, INFINITE );
Mat tmp0, tmp1, tmp2, tmp3, tmp4;
tmp4 = img;
bilateralFilter(img, tmp0, -1, 50, 5);
Canny(tmp0, tmp1, 35, 200, 3);
/*imwrite("test.jpg",tmp3);
waitKey(1);*/
ReleaseMutex( syncMutex );
WaitForSingleObject( syncMutex, INFINITE );
imshow("ServerWindow", tmp1);
ReleaseMutex( syncMutex );
waitKey(1);
cout << img.cols << " number cols after show \n";
is_data_ready = 0;
ReleaseMutex( hMutex1 );
waitKey(1);
//connect();
return 0;
void quit(string msg, int retval)
int connect()
/*WSADATA wsaData;
int iResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;*/
struct addrinfo *result = NULL;
struct addrinfo hints;
ListenSocket = INVALID_SOCKET;
ClientSocket = INVALID_SOCKET;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0)
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 )
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET)
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR)
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR)
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET)
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
// No longer need server socket
closesocket(ListenSocket);
return 0;
编辑: 如果按照建议添加测试如果 tmp1 为空,我会得到另一个异常:
bilateralFilter(img, tmp0, -1, 50, 5);
Canny(tmp0, tmp1, 35, 200, 3);
//ytp = frame;
//testImage = frame;
imwrite("test.jpg",tmp3);
waitKey(1);
waitKey(500);
ReleaseMutex( syncMutex );
WaitForSingleObject( syncMutex, INFINITE );
if (tmp1.empty())
std::cout << "tmp1 is empty" << std::endl;
break;
imshow("ServerWindow", tmp1);
程序现在在 imwrite 上崩溃并抛出异常: newCVS2.exe 中 0x67BDFF1F (msvcr110d.dll) 处的未处理异常:0xC0000005:访问冲突读取位置 0x67706A2E。
这让我觉得访问垫子有问题
【问题讨论】:
【参考方案1】:检查tmp1
是否不为空,例如
if (tmp1.empty)
std::cout << "tmp1 is empty" << std::endl;
break;
我注意到 OpenCV 的 imshow
函数不是线程安全的(至少在 Windows 机器上)。例如,如果我从两个不同的线程调用imshow
,我的程序就会崩溃。如果我在一个线程中调用namedWindow()
命令,然后在另一个线程中调用imshow()
命令,程序也会崩溃。所以确保你不要那样做。作为旁注,最好在调用imshow
之前使用namedWindow("ServerWindow")
创建一个输出窗口。仅在调用imshow
的同一线程中创建此窗口一次(在for
循环之外)。这将提高性能并可能解决问题。
【讨论】:
感谢您的好评。我尝试添加 tmp1.empty 行,现在程序崩溃并给出异常:newCVS2.exe 中 0x67BDFF1F (msvcr110d.dll) 处的未处理异常:0xC0000005:访问冲突读取位置 0x67706A2E。程序在 imwrite 行崩溃。这太奇怪了。我已经用信息更新了主帖 如果我真的打电话:namedWindow("ServerWindow",CV_WINDOW_AUTOSIZE);我得到了异常:newCVS2.exe 中 0x66796AF8 (opencv_highgui248d.dll) 处的未处理异常:0xC0000005:访问冲突读取位置 0x69577265。在那条线上 @Arnagath 您可能正在从多个线程访问tmp1
指向的数据。您的程序使用imwrite
的原因可能是因为imwrite
访问磁盘,因此执行时间较长。在imwrite
执行期间,其他线程可能完成对共享数据的访问(例如tmp1指向的数据),所以没有例外。尝试使访问Mat
线程安全。最重要的是,通过保护共享数据不被同时访问,确保您的程序是线程安全的。
另外请注意,当您分配 Mat image = other_image;
时,image
和 other_image
都指向的不是完全相同的数据。所以通过更改image
,other_image
也将被更改。【参考方案2】:
因为tmp3
只是初始化,没有任何数据。尝试编写 tmp0
或 tmp1
将在此代码中起作用。
【讨论】:
你误会了,imwrite 不会导致问题,使用 imwrite 可以解决问题。我们有一个空的 tmp3 的原因是为了减少保存图像所需的时间。仅当我们之前没有 imwrite 时,程序才会在 imshow 上崩溃。写 tmp0, tmp1 tmp3 一切正常,这是我什么都不写的时候。哈哈,我看到它令人困惑,但不知道如何更好地制定:P 你有没有尝试在使用imwrite的区域使用waitkey(500)? (保持 imwrite 被注释掉) 我刚试过,waitkey(5000) 无济于事,仍然在imshow 崩溃。即使我没有看到它在单步执行时跳到任何地方,也感觉像是一个并发问题。以上是关于openCV、C++ 并发、windows的主要内容,如果未能解决你的问题,请参考以下文章
c++结合opencv能给载入图像并处理,我想知道,c++结合啥,可以实现处理gif图像