尝试在c#线程中访问受保护的内存时出错

本文关键字:受保护 内存 出错 访问 线程 | 更新日期: 2023-09-27 18:19:47

我有两个声明为全局的线程。在表单加载时,我启动两个线程。在退出按钮上单击"我正在尝试中止这两个线程,如果它们是活动的或是连接的。"。但我收到了这个错误"试图读取写保护内存",应用程序有时会挂起。在一个线程中,我正在创建一个管道并等待while循环中的连接,而在另一个线程上,我正在更新后台表单上的数据网格

任何正在发生的事情的想法。如果我的问题不够清楚,但代码很大,我可以发布代码。

感谢

表单加载的代码是

private void frmStatus_Load(object sender, EventArgs e)
{
    Control.CheckForIllegalCrossThreadCalls = false;
    RefreshStatus = new Thread(RefreshStatusForm);
    RefreshStatus.IsBackground = true;
    RefreshStatus.Start();
    th = new Thread(this.CreatePipe);
    th.IsBackground = true;
    th.Start();
}

关闭表单的代码在按钮上点击

private void btnOk_Click(object sender, EventArgs e)
{
    try
    {
        System.Object lockThis = new System.Object();
        lock (lockThis)
        {
            bCheckVal = false;
            if (!this.bComplete)
                stopOperation();
            Thread.Sleep(1000);
            ////////These are the lines in which i get the error 
            if (!th.IsAlive) 
            {
                th.Join();
            }
            else
            {
                th.Abort();
            }
            this.bRefresh = false;
            Thread.Sleep(1000);
            if (RefreshStatus.IsAlive)
            RefreshStatus.Abort();
            else
            RefreshStatus.Join();
            /////////////////
            this.bFlag = true;
        }
        this.Close();           
    }
    catch (System.Exception ex)
    {
    }
}

由线程执行的代码

        public  void CreatePipe()
    {
        try
        {
            PipeSecurity pipeSa = new PipeSecurity();
            pipeSa.SetAccessRule(new PipeAccessRule("Everyone",
                            PipeAccessRights.ReadWrite, AccessControlType.Allow));
            NamedPipeServerStream pipeServer = new NamedPipeServerStream(
                this.strguid,                    // The unique pipe name.
                PipeDirection.InOut,            // The pipe is bi-directional
                NamedPipeServerStream.MaxAllowedServerInstances);
            string strMessage = string.Empty;
            char[] bRequest = new char[BUFFER_SIZE];// Client -> Server
            int cbBytesRead, cbRequestBytes;
            StreamReader sr = null;
            byte[] bReply;                          // Server -> Client
            int cbBytesWritten, cbReplyBytes;
            int icount = 0;
            List<string> lsRead = new List<string>();
            cbBytesRead = 0;
            CopyFileThread = new Thread(this.CopyFile);
            CopyFileThread.IsBackground = true;
            CopyFileThread.Start();
            bool bflag = false;

            while (true)
            {
                this.bComplete = false;
                bWait = true;
                try
                {


                    pipeServer.WaitForConnection();
                    sr = new StreamReader(pipeServer);
                    //string message = sr.ReadToEnd();
                    bWait = false;
                    cbRequestBytes = BUFFER_SIZE;



                    string pipeData = string.Empty;
                    pipeData = sr.Read(bRequest, 0, 255).ToString().Trim();
                    strMessage = new string(bRequest);


                    strMessage = strMessage.Replace("'0", string.Empty);
                    if (strMessage.Contains("Aborted"))
                    {

                        if (pipeServer.IsConnected)
                        {
                            pipeServer.Flush();
                            pipeServer.Disconnect();
                        }
                        break;
                    }
                    else
                        if (strMessage.Contains("Completed"))
                        {
                            if (progressBar1.InvokeRequired)
                            {
                                strPercent = "100%";
                            }

                            if (pipeServer.IsConnected)
                            {
                                pipeServer.Flush();
                                pipeServer.Disconnect();
                            }
                            this.bComplete = true;
                            break;
                        }
                    // 26 dec 2011 Comment code //////
                    if (strMessage == "")
                    {
                        progressBar1.Visible = false;
                        progressBar2.Visible = true;
                    }
                    else
                    {
                        progressBar1.Visible = true;
                        progressBar2.Visible = false;
                    }
                    //// 26 dec 2011 Comment code //////
                    string[] strStatusMessages = strMessage.Trim().Split(',');

                    // 26 dec 2011 Comment code //////
                    pipeServer.Flush();
                    pipeServer.Disconnect();

                }
                catch (System.Exception ex)
                {
                    //MessageBox.Show(ex.ToString());
                }
            }

            pipeServer.Close();

            if (CopyFileThread.IsAlive)
                CopyFileThread.Abort();
            else
                CopyFileThread.Join();

            MessageBox.Show("Exiting from createpipe 2 Thread :{0}", Thread.CurrentThread.ToString());
            return;
        }
        catch (Exception ex)
        {
            return;
        }
    }

//////////////////////////////

void RefreshStatusForm(){

        while (bRefresh)
        {
            if (iRefresh == 1)
            {
                GetRefresh();
                iRefresh = 0;
            }
            else if (iRefresh == 2)
                break;
            Thread.Sleep(1000);
        }
        MessageBox.Show("Exiting from RefreshStatusForm 2 Thread :{0}", Thread.CurrentThread.ToString());
    }

尝试在c#线程中访问受保护的内存时出错

您不需要中止或加入线程。最好让他们正常完成。在执行"在while循环中等待连接"的线程中,while循环条件设置为bool,当您退出程序时,将bool设置为false。对其他线程也执行类似的操作。

编辑1所以首先:

while (true)
            {
                this.bComplete = false;
                bWait = true;
                try
                {

应该是类似的东西

while(Running) {

您使用

pipeServer.WaitForConnection(); 

它会阻塞线程,所以我会将其更改为异步任务

    BeginWaitForConnection(
    AsyncCallback callback,
    Object state
)

但如果你不想这样做,那么每隔一段时间就会添加一个超时。

然后在中

void btnOk_Click

你所需要做的就是设置

Running = false;
bRefresh = false; 

那么线程将自己完成。

EDIT2

使用进行设置

AsyncCallback myCallback = new AsyncCallback(AsyncPipeCallback);  
pipeServer.BeginWaitForConnection(myCallback, null); 

添加此方法:

private void AsyncPipeCallback(IAsyncResult Result)  
{   
    try  
    {  
        pipeServer.EndWaitForConnection(Result);  
            sr = new StreamReader(pipeServer);
                    //string message = sr.ReadToEnd();
                    bWait = false;
                    cbRequestBytes = BUFFER_SIZE;



                    string pipeData = string.Empty;
                    pipeData = sr.Read(bRequest, 0, 255).ToString().Trim();
                    strMessage = new string(bRequest);


                    strMessage = strMessage.Replace("'0", string.Empty);
                    if (strMessage.Contains("Aborted"))
                    {

                        if (pipeServer.IsConnected)
                        {
                            pipeServer.Flush();
                            pipeServer.Disconnect();
                        }
                        break;
                    }
                    else
                        if (strMessage.Contains("Completed"))
                        {
                            if (progressBar1.InvokeRequired)
                            {
                                strPercent = "100%";
                            }

                            if (pipeServer.IsConnected)
                            {
                                pipeServer.Flush();
                                pipeServer.Disconnect();
                            }
                            this.bComplete = true;
                            break;
                        }
                    // 26 dec 2011 Comment code //////
                    if (strMessage == "")
                    {
                        progressBar1.Visible = false;
                        progressBar2.Visible = true;
                    }
                    else
                    {
                        progressBar1.Visible = true;
                        progressBar2.Visible = false;
                    }
                    //// 26 dec 2011 Comment code //////
                    string[] strStatusMessages = strMessage.Trim().Split(',');

                    // 26 dec 2011 Comment code //////
                    pipeServer.Flush();
                    pipeServer.Disconnect();

    }  
    catch { }
    if(Running)
        pipeServer.BeginWaitForConnection(myCallback, null); 
} 

现在,当连接发生时,将调用AsyncPipeCallback。然后,当它完成时,检查它是否仍在运行,如果是,则再次开始WaitForConnection。

在btnOk_Click中将其更改为:

private void btnOk_Click(object sender, EventArgs e)
{
    try
    {
        System.Object lockThis = new System.Object();
        lock (lockThis)
        {
            bCheckVal = false;
            if (!this.bComplete)
                stopOperation();
            Thread.Sleep(1000);
            Running  = false;
            bRefresh = false;
            this.bFlag = true;
        }
        this.Close();           
    }
    catch (System.Exception ex)
    {
    }
}

"试图读取或写入受保护的内存"通常意味着您有一个垃圾指针或指针算术超出了界限。垃圾指针还可能导致应用程序挂起或以难以重现的方式崩溃。

为了回答线程问题,IMO最简单的解决方案是使用.NET 4.0任务而不是线程。可以使用取消令牌构造任务。您的主线程可以使用该取消令牌向任务线程发出关闭商店回家的信号。

相关文章: