我所遇见的坑(二)

起因

前些天,查找一个ActiveX项目的问题。问题比较难定位,并且源码不怎么易读。表现:在绝大多数电脑上运行没有问题,但在个别电脑上100%会出现IE崩溃,并且在一些其他电脑上操作多次也会出现IE崩溃。经过多番调试,总算找到了原因。原来罪魁祸首是写文件日志 。

stream != NULL

首先先看这个报错图:

在这里插入图片描述

再看一下项目的代码(已经经过略微修改):

#include <afx.h>
#include "stdafx.h"

#include <iostream>
#include <fstream>
#include <afxdisp.h>
using namespace std;
void write(CString str,CString sErrorMsg)
{
	 fstream _file;
	_file.open(str+L"/logs", ios::in);
	if(!_file)
	{
		::CreateDirectory(str+L"/logs/",NULL);
	}
	
	CStdioFile* pTxtFile = new CStdioFile();
	try{

		COleDateTime time=COleDateTime::GetCurrentTime();
		CString logname=L"/"+time.Format(L"%Y-%m-%d")+L".log";

		CStdioFile* pTxtFile = new CStdioFile();

		if(!pTxtFile->Open(str+L"/logs/"+logname,CFile::modeReadWrite | CFile::typeText))
		{
			pTxtFile->Open(str+L"/logs/"+logname,CFile::modeWrite | CFile::modeCreate);
		}  
		try
		{ 
			if(pTxtFile->GetLength()>50*1024*1024)
			{
				pTxtFile->SetLength(0);
			}
			CString str=time.Format(L"%Y-%m-%d %H:%M:%S") + L"------" + sErrorMsg;

			pTxtFile->SeekToEnd();
			pTxtFile->WriteString(str);
			pTxtFile->WriteString(L"\n");
			pTxtFile->Close();
		}catch (...) {
			pTxtFile->Close();
		}
		delete pTxtFile;
	}catch(...){
		delete pTxtFile;
	}
}
int _tmain(int argc, _TCHAR* argv[])
{
	for(int i=0;i<1000;i++)
	{
		write("C:\\","err2");
	}
	system("pause");
	return 0;
}

项目里是固定写C盘,这点很尴尬,因为C盘你不一定有权限写文件,而且用户电脑有可能就没有C盘这个盘符(是的,Windows并没有规定必须有C盘)。考虑到用户安装系统可能装在其他盘,以及权限问题,解决这个问题很简单,判断一下当前系统的盘符,同时申请管理员权限,保证能有写权限即可。

下面来看为什么有的电脑偶尔会出现IE崩溃的问题:

首先要知道IE标签页是多线程的,意味着每开一个标签页都需要多出几个线程(至于为什么不是多出来一个,你认为一个线程能支撑起一个标签页的所有活动吗?)。这样就会涉及到多线程写文件的问题,本着严谨追求的态度,特意去模拟了下该场景,以下代码多运行几次,就会报错:

#include <afx.h>
#include "stdafx.h"

#include <iostream>
#include <fstream>
#include <afxdisp.h>
using namespace std;
void write(CString str,CString sErrorMsg)
{
	 fstream _file;
	_file.open(str+L"/logs", ios::in);
	if(!_file)
	{
		::CreateDirectory(str+L"/logs/",NULL);
	}
	
	CStdioFile* pTxtFile = new CStdioFile();
	try{

		COleDateTime time=COleDateTime::GetCurrentTime();
		CString logname=L"/"+time.Format(L"%Y-%m-%d")+L".log";

		CStdioFile* pTxtFile = new CStdioFile();

		if(!pTxtFile->Open(str+L"/logs/"+logname,CFile::modeReadWrite | CFile::typeText))
		{
			pTxtFile->Open(str+L"/logs/"+logname,CFile::modeWrite | CFile::modeCreate);
		}  
		try
		{ 
			if(pTxtFile->GetLength()>50*1024*1024)
			{
				pTxtFile->SetLength(0);
			}
			CString str=time.Format(L"%Y-%m-%d %H:%M:%S") + L"------" + sErrorMsg;

			pTxtFile->SeekToEnd();
			pTxtFile->WriteString(str);
			pTxtFile->WriteString(L"\n");
			pTxtFile->Close();
		}catch (...) {
			pTxtFile->Close();
		}
		delete pTxtFile;
	}catch(...){
		delete pTxtFile;
	}
}
unsigned long WINAPI Fun(LPVOID lpParamter)
{
    int iRunTime = 0;
    while(++iRunTime<1000)//执行100次跳出
    {
       write("C:\\","err1");
    }
    ExitThread(-1);
}
void Work()
{
	unsigned long ulThreadId = 0;
	HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, &ulThreadId);
}
int _tmain(int argc, _TCHAR* argv[])
{
	Work();
	for(int i=0;i<1000;i++)
	{
		write("C:\\","err2");
	}
	system("pause");
	return 0;
}

虽然在项目中我们并没有写多线程,但是IE是多线程的。实际项目中ActiveX需要调用硬件,那么就会出现线程竞争一个文件的问题。这个问题主要出现写代码不严谨,很多时候一点细微的地方会影响整个项目的运行。解决方案:在写日志的时候加锁即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值