这周感触很大,和硬件实时交互以后,出现很多问题,数据接受的问题,程序奔溃问题,数据显示问题接踵而至,感觉很挫败,然而没办法只能一个一个解决,首先我先处理的接受方面的问题,在接受方面,程序奔溃主要原因是接受数据子线程和主线程数据使用的时候会遇到。下面说一下出现这种问题可能的原因。(我的数据是这样的,一个vector容器中放着结构体,结构体里面放着一个整形(int)一个deque容器,主要出问题是deque容器中)
第一个原因首先考虑你对全局变量的保护问题吧!一开始我也没有考虑这个问题,因为我使用了临界区了呀,为什么还会出现问题呢!然后就像疯了一样,网上各种找方法,找问题,然后网上各种答案也有,都尝试了,没有效果,还是在运行一段时间后出现问题,这个跨线程的问题还不好定位,最后找到了一种定位方法,就是在编译器中的堆栈部分查看(本人用的vs2010),定位到问题,不是在主线程从子线程中接受数据出现问题,就是在子线程中接受数据的时候出现,最后就和一些群里面的“大拿”聊我这个问题,也和一些我的好友聊,我的一位好友说,是不是全局变量同步出现的问题呀,我说我也用临界区保护了呀,还会有问题,他说把互斥量也加上,试试效果,我才加上互斥量,结果问题解决了,这里贴出我使用临界区和互斥量的部分:
//先定义临界区和互斥量
CRITICAL_SECTION g_cs; //定义一个临界区对象,用来保护变量
HANDLE g_hMutex = INVALID_HANDLE_VALUE; // 定义一个互斥量用来进行数据同步
//下面是线程中的代码
InitializeCriticalSection(&g_cs); //初始化临界区
g_hMutex = CreateMutex(NULL, FALSE, "Mutex"); //创建互斥量
while( g_MarkReceive ) //g_MarkReceive 这个值开始为1,当接受失败置为0
{
if (!g_hMutex)
{
MessageBox(NULL, "Failed to CreateMutex !", "", MB_OK);
return;
}
EnterCriticalSection(&g_cs); //进入临界区
WaitForSingleObject(g_hMutex, INFINITE); // INFINITE: 长时间等待
char buf[32768];
SOCKET* sock=(SOCKET*)param;
int bytes;
if((bytes=recv(*sock,buf,sizeof(buf),0))==SOCKET_ERROR)
{
g_MarkReceive = 0;
MessageBox(NULL, "接受数据失败(服务器已断开)!", "", MB_OK);
return;
}
buf[bytes]='\0';
std::string strTmp = buf;
std::vector<std::string> vectStrTmp;
split(strTmp, ",", vectStrTmp);
vectStrTmp.pop_back();
/****这一部分是就是将vectStrTmp中的数据,赋值给全局变量中****/
ReleaseMutex(g_hMutex); // 释放资源
LeaveCriticalSection(&g_cs); // 离开临界区
}
当然在主线程中也最好加上临界区和互斥量防止主线程这边全局变量取值到局部变量的时候出问题。这是为的最终解决方法。下面说一下,其他需要注意到的:
1、在查找原因的时候,其中一篇是这样说的,deque容器在clear的时候,容器的地址会改变,会重新附地址。
2、在使用互斥锁的时候一定要注意不要出现死锁,我这个只是mutex的简单应用,网上有很多自定义对mutex的扩展。
附加代码split字符串分割代码:
void split(const std::string& src, const std::string& separator, std::vector<std::string>& dest)
{
int separate_characterLen = separator.size();//分割字符串的长度,这样就可以支持如“,,”多字符串的分隔符
int lastPosition = 0,index = -1;
while (-1 != (index = src.find(separator,lastPosition)))
{
dest.push_back(src.substr(lastPosition,index - lastPosition));
lastPosition = index + separate_characterLen;
}
std::string lastString = src.substr(lastPosition);//截取最后一个分隔符后的内容
if (!lastString.empty())
dest.push_back(lastString);//如果最后一个分隔符后还有内容就入队
}