多线程调用dll,时不时出错
我调用一个验证码识别程序的dll来识别电话,同时开5个线程,不时地出错,并且停止全部线程及其父线程后,并sleep 200秒,再次调用,大部分时候还是出错!
调用代码:
hftClass.pic picc = new hftClass.pic();
err = picc.getPicWord(para, ref root, ref urlRef, ref val);
picc.Dispose();
picc = null;
picc:
public class pic : IDisposable
{
下面两个函数是调用验证码的
[DllImport("ycode.dll")]
public static extern int loadcode(int code, int Length, IntPtr address, IntPtr pass);
[DllImport("ycode.dll")]
public static extern IntPtr Recognitiond(int ItemNo, int picin, int Length, IntPtr Address1, IntPtr Address2);
取电话号码
public Pub.errCode getPicWord(string[] para, ref string root, ref string urlref, ref string tel)
{
string tel101 = "";
string[] urlpic = new string[0];
int ii = 0;
if (para[1] == "")
{
//用con取
urlpic = para[0].Split("‖".ToCharArray());
}
else
{
MatchCollection mc101 = hString.getMatchs(para[0], para[1]);
if (mc101 != null)
{
urlpic = new string[mc101.Count];
for (int i = 0; i < mc101.Count; i++)
{
for (int j = 1; j < mc101[i].Groups.Count; j++)
{
if (mc101[i].Groups[j].Value != "")
{
urlpic[i] = mc101[i].Groups[j].Value;
}
}
}
}
}
bool recoge = true;
//先下载图片到本地
for (int ij = 0; ij < urlpic.Length; ij++)
{
if (urlpic[ij] == "")
continue;
urlpic[ij] = hWeb.Href.makeHref(urlpic[ij], root, urlref);
urlpic[ij] = hWeb.WebDbo.getHttpPicFile(urlpic[ij], urlref);
recoge = recoge & (!string.IsNullOrEmpty(urlpic[ij]));
}
if (!recoge) //如果一个也没有取到
{
return Pub.errCode.图片文件不存在;
}
//else
//{
// System.Windows.Forms.Application.DoEvents();//
// //System.Threading.Thread.Sleep(200);
//}
try
{
用不用lock都一样
object obj = new object();
lock (obj)
{
IntPtr ipPath = Marshal.StringToHGlobalAnsi(para[3]);
IntPtr ipPass = Marshal.StringToHGlobalAnsi(para[4]);
大部分错误在此,因为调用的识别验证码文件库一致,dll文件也一致,就在此处出错,错误:
尝试读取或写入受保护的内存。这通常指示其他内存已损
我不知道这个dll是不是多线程安全的。
但在服务器上(8核,intel),这种现象就很少,同样是开5个线程。而在我的机器上(2核,AMD),就容易出问题,最主要的是,出问题后错误清除不了,会一直错下去,我不知道是什么原因,请各位大侠指点!
ii = loadcode(0, 0, ipPath, ipPass);
if (ii != 1)
{
Pub.errDes err = new Pub.errDes();
err.errType = Pub.errMode.Data;
err.errPage = "Method";
err.errFun = "getPicWord";
err.errMes = "打开识别库失败";
Pub.writeErr(err);
//Pub.writeErr(Pub.errMode.Scan, "Method", "getPicWord", "打开识别库失败", "");
return Pub.errCode.打开识别库失败;
}
for (int ij = 0; ij < urlpic.Length; ij++)
{
if (urlpic[ij] == "")
continue;
// urlpic[ij] = hWeb.Href.makeHref(urlpic[ij], root, urlref);
IntPtr ptrIn = Marshal.StringToHGlobalAnsi(urlpic[ij]);
string tttt = "";
IntPtr ptrFile = Marshal.StringToHGlobalAnsi(tttt);
IntPtr no1 = Recognitiond(1, 0, 0, ptrFile, ptrIn);//取文字识别指针
tel101 = Marshal.PtrToStringAnsi(no1);
if (tel101 != "")
{
if (tel101.IndexOf("?") < 0)
{
if (tel == "")
{
tel = tel101;
}
else
{
if (tel.IndexOf(tel101) < 0)
{
tel = tel + "‖" + tel101;
}
}
}
}
}
}
return Pub.errCode.完成;
}
catch (Exception ee)
{
Pub.errDes err = new Pub.errDes();
err.errType = Pub.errMode.Error;
err.errPage = "Method";
err.errFun = "getPicWord";
err.errMes = ee.Message;
err.errOther = urlref;
Pub.writeErr(err);
if (ee.Message.IndexOf("尝试读取或写入受保护的内存") > -1)
{
我在此控制,停止所有线程,置其父线程为null,并在最上级线程中,用timer进行再次启动
return Pub.errCode.需要重启;
// return Pub.errCode.完成;
}
else
{
// Pub.writeErr(Pub.errMode.Scan, "Method", "getPicWord", ee.Message, urlref);
//return Pub.errCode.未取到电话;
return Pub.errCode.完成;
}
}
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
连续三次出错后,我会清除他们的父线程:
public void Dispose()
{
if (Pub.intTh > 0)
{
//说明还有线程在工作,就不能关闭
Pub.bEnd = true;
int i = 0;
while (Pub.intTh > 0)
{
//Pub.strGetNow = "正在结束进程,请稍候!!!" ;
// Application.DoEvents();
Thread.Sleep(2000);
i++;
if (i > 99)//强制关掉
break;
}
}
if (thTimer != null)
{
thTimer.Dispose();
thTimer = null;
}
if (dtScan != null)
{
dtScan.Dispose();
dtScan = null;
}
bDoing = false;
alive = false;
tha = null;
GC.SuppressFinalize(this);
}
再在上级线程中:
先清除包含子线程的类实例th(线程在类实例th中启动)
if (th != null)
{
if (th.alive == true)
{
//检查循环是否还在继续
if (th.lastDone.AddMinutes(10) < DateTime.Now)
{
//说明很长时间没有循环了
bDoing = true;
th.Dispose();
th = null;
Thread.Sleep(200000); //等待200秒, 不知道是不是这个时间不够
}
else
{
return;
}
}
else
{
bDoing = true;
th.Dispose();
th = null;
Thread.Sleep(200000);
}
}
再重新开
Pub.bEnd = false;
th = new thclass2();
请各位对dll调用比较熟练的大侠指点!