当前位置: 代码迷 >> C# >> 三个线程以上调用验证码识别DLL时出现异常:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。求解,解决加分至100分,多谢
  详细解决方案

三个线程以上调用验证码识别DLL时出现异常:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。求解,解决加分至100分,多谢

热度:342   发布时间:2016-04-28 08:34:46.0
三个线程以上调用验证码识别DLL时出现错误:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。求解,解决加分至100分,谢谢!
using DotNet.Utilities;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

namespace 修改Post
{
    public class Rename:LeWell.Api.ISuperJob,LeWell.Api.ILocoySpider
    {

        #region ISuperJob 成员

        public void ChangeArticle(int level, Dictionary<string, List<string>> dic, string pageurl, string html)
        {
           
        }
        public string ChangeHtml(int level, string originalHtml, System.Net.WebHeaderCollection request, System.Net.WebHeaderCollection response, string pageurl)
        {
            if (pageurl.IndexOf("^") > 0)
            {
                string[] urls = pageurl.Split('^');
                
                string sPath = AppDomain.CurrentDomain.BaseDirectory + "\\PostCookie.ini";
                if ( urls.Length >2)
                {
                    sPath = AppDomain.CurrentDomain.BaseDirectory + "\\" + urls[2];
                }
                //MessageBox.Show(sPath);
                string cookieContainer = "";
               
                string bianma = "";
               
                string ImgURL = "";
                string searchfile="";
                string code = "";
                string ContentType = "application/x-www-form-urlencoded";
                string Referer = "";
                if (File.Exists(sPath))
                {
                    ClsIniFile ini = new ClsIniFile(sPath);
                    bianma = ini.IniReadValue("BianMa", "bianma");
                    cookieContainer = ini.IniReadValue("Cookie", "cookie");
                    ImgURL = ini.IniReadValue("CodeUrl", "codeurl");
                    searchfile = ini.IniReadValue("SearchFile","searchfile");
                     code = ini.IniReadValue("Error", "error");
                     ContentType = ini.IniReadValue("ContentType", "contenttype");
                     Referer= ini.IniReadValue("Referer", "referer");
                    var s = ini.IniReadValue("Stop", "stop");
                   
                }
                string postdata = urls[1];

                string yzm = "";      
                string postdata2 = postdata;

                if (ImgURL.Length > 2)
                {
                    yzm = GetYzm(ImgURL, cookieContainer,bianma);

                    if (yzm.Length < 1)
                    {
                        Thread.Sleep(1000);
                        yzm = GetYzm(ImgURL, cookieContainer,bianma);

                        if (yzm.Length < 1)
                        {
                            return "验证码识别错误";
                        }
                    }

                    postdata2 = postdata + yzm;
                }
                originalHtml = GetPost(urls[0], postdata2, cookieContainer, bianma, ContentType, Referer);
                    if (originalHtml.IndexOf(code) > 0)
                    {
                        return "验证码识别错误";
                    }

                    if (searchfile.Length > 2)
                    {
                        originalHtml = GetSearch(searchfile, cookieContainer,bianma);
                       // panduan = true;
                    }
            }
            return originalHtml;
        }

        public void ChangeWebRequest(int level, ref System.Net.HttpWebRequest request)
        {
        }

        public string GetMultPageUrl(string multPageName, string pageurl, string html, string multPageStyle, string multPageCombine)
        {
            return html;
        }

        public List<string> GetPagesUrl(int level, string pageurl, string html, string pagesStyle, string pagesCombine)
        {
            return null;
        }

        public bool UseChangeWebRequest
        {
            get { return false; }
        }

        public bool UseGetMultPageUrl
        {
            get { return false; }
        }

        public bool UseGetPagesUrl
        {
            get { return false; }
        }
        #endregion

        #region ICloneable 成员

        public object Clone()
        {
            return this.MemberwiseClone();
        }

        #endregion

        #region IDisposable 成员

        public void Dispose()
        {
            throw new NotImplementedException();
        }
        #endregion
        #region ILocoySpider 成员
       // string p
        public int index = 0;     
        //加载 识别引擎
        [DllImport("CaptchaOCR.dll")]
        public static extern int VcodeInit(string PassWord);
        [DllImport("CaptchaOCR.dll")]
        //GetVcode 获取识别结果
        public static extern bool GetVcode(int Index, byte[] ImageBuffer, int ImgBufLen, StringBuilder Vcode);
        [DllImport("CaptchaOCR.dll")]
        public static extern int FreeVcode();

        public void ChangeResultDic(Dictionary<string, string> dic)
        {          
        }
        /// <summary>
        /// 用标题给文件命名
        /// </summary>
        /// <param name="fieldandfiles"></param>
        /// <param name="dic"></param>
        public void ChangeSaveFiles(Dictionary<string, Dictionary<string, KeyValuePair<string, string>>> fieldandfiles, Dictionary<string, string> dic)
        {
           
        }
        public string ChangeStepHtml(string pageurl, string html, System.Net.WebHeaderCollection request, System.Net.WebHeaderCollection response)
        {
            
            return html;
        }

        public string GetSearch(string url, string  cookieContainer,string bianma)
        {
             HttpHelper http = new HttpHelper();
                HttpItem item = new HttpItem()
                {
                    URL = url,//URL这里都是测试     必需项
                    UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)",//用户的浏览器类型,版本,操作系统     可选项有默认值
                    Accept = "text/html, application/xhtml+xml, */*",
                    ContentType = "application/x-www-form-urlencoded",
                 //   Encoding = Encoding.GetEncoding( bianma),
                    Method = "get",//URL     可选项 默认为Get
                    ResultType = ResultType.String ,
                    ProxyIp = "ieproxy",
                    Cookie = cookieContainer
                };
                //得到HTML代码
                HttpResult result = http.GetHtml(item);
            return result.Html;
        }

        public string  GetYzm(string url, string cookieContainer,string bianma)
        {

              HttpHelper http = new HttpHelper();
                HttpItem item = new HttpItem()
                {
                    URL = url,//URL这里都是测试     必需项
                 //   Encoding = Encoding.GetEncoding(bianma),
                    Accept = "image/png, image/svg+xml, image/*;q=0.8, */*;q=0.5",
                    ContentType = "application/x-www-form-urlencoded",
                    Method = "get",//URL     可选项 默认为Get
                    ResultType = ResultType.Byte,
                    ProxyIp = "ieproxy",
                    Cookie = cookieContainer
                };
                //得到HTML代码
                HttpResult result = http.GetHtml(item);
                byte[] bytes = result.ResultByte;
                FreeVcode();
                index = VcodeInit("9E8228E78634F5BF7123521032B57600");//为防止 他人调用 给引擎 设置了 密码 不是绑定机器的
                if (!(index == -1))
                {

                    StringBuilder Result = new StringBuilder('\0', 20);
                    ////开始识别 
                    GetVcode(1, bytes, bytes.Length, Result);
                    return  Result.ToString();
                }
                return "0"; 
            }
        public string GetPost(string posturl, string postData, string cookieContainer, string bianma, string ct, string rf)
        {
            if (bianma.Length<3)
            {
                bianma = "uft-8";
            }
            HttpHelper http = new HttpHelper();
            HttpItem item = new HttpItem()
            {
                URL = posturl,//URL这里都是测试     必需项
                Accept = "text/html, application/xhtml+xml, */*",
                Referer = rf,
                ContentType = ct,
               // Encoding = Encoding.GetEncoding(bianma),
               // Accept-Encoding = "gzip,deflate",
                Method = "POST",//URL     可选项 默认为Get
                ResultType = ResultType.String,
                Cookie = cookieContainer,
                ProxyIp = "ieproxy",
                PostDataType = PostDataType.Byte,
                PostdataByte = Encoding.GetEncoding(bianma).GetBytes(postData )
            };
            HttpResult result = http.GetHtml(item);
            return result.Html;
           
        }
       
        public void ChangeStepRequest(ref System.Net.HttpWebRequest request)
        {
           
        }

        public string EndJob(bool handstop,string jobname, string jobid, int url, int content, int post, object job)
        {
            return null;
        }

        public List<KeyValuePair<string, Dictionary<string, string>>> GetStepUrls(string html, string areaStart, string areaEnd, string urlStyle, string urlCombine, string allow, string forbidden)
        {
            return null;
        }

        public List<string> MakeStartAddress(string urlData, string useragent, string refer, System.Net.CookieCollection cookie)
        {
            return null;
        }

        public string StartJob()
        {
            return null;
        }

        public bool UseChangeSaveFiles
        {
            get { return true; }
        }

        public bool UseGetStepUrls
        {
            get { return false; }
        }

        public bool UseMakeStartAddress
        {
            get { return false; }
        }

        #endregion
    }
}
.
单线程没问题,二线程也基本正常,当三线程以上时会出现以下错误:
当前页出现错误:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。Boolean GetVcode(Int32, Byte[], Int32, System.Text.StringBuilder) 
请大侠们解决,谢谢,最好直接将修改好的代码贴出,谢谢
------解决思路----------------------
你可以写


              if (!(index == -1))
                {
                    lock(typeof(Rename)
                    {
                      StringBuilder Result = new StringBuilder('\0', 20);
                      ////开始识别 
                      GetVcode(1, bytes, bytes.Length, Result);
                      return  Result.ToString();
                    }
                }
------解决思路----------------------
那就在调用验证码的地方加锁,不让并发访问
------解决思路----------------------
Boolean GetVcode(Int32, Byte[], Int32, System.Text.StringBuilder) 
应该是API非线程安全
调用的时候加锁就可以
------解决思路----------------------
CaptchaOCR
这东西本身支持多线程吗?
VcodeInit的返回值和GetVcode的第一个参数完全没关联吗?
FreeVcode这函数没有参数,那它的作用是什么?把整个库的内存free掉?那你多线程调用第二个线程岂不是会把第一个线程需要的内存给删了?
------解决思路----------------------
引用:
Quote: 引用:

Boolean GetVcode(Int32, Byte[], Int32, System.Text.StringBuilder) 
应该是API非线程安全
调用的时候加锁就可以

能指出哪一句替换为哪一句,或在哪一句后面加上哪一句么?谢谢了。

使用lock给非线程安全的函数加锁
示意代码:

class  yourclass
{ 
      private static object lockObject = new object();

       public  Getyzm(...)
    {
                ...
                lock(lockObject)
                 {
                       GetVcode(1, bytes, bytes.Length, Result); 
                 }
               ...
        }


如果加锁后,仍然报错,那就该查自己的数据处理逻辑了
5楼说的比较详细
  相关解决方案