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

时间:2012-01-06 07:20:11

标签: c# multithreading

我有两个被声明为global的线程。在表单加载时我启动两个线程。在退出按钮上单击我试图中止这两个线程,如果它们还活着或者加入。但是我得到这个错误“试图读取写保护的内存“并且应用程序有时挂起。在一个线程中我创建一个管道并在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());
    }

2 个答案:

答案 0 :(得分:1)

您无需中止或加入该主题。最好让他们正常完成。在“等待while循环连接”的线程中,将while循环条件设置为bool,当退出程序时将bool设置为false。与其他线程做类似的事情。

<强> EDIT1 首先是:

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。然后当它完成时,检查它是否仍然在运行,如果它再次是BeginWaitForConnection。

在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)
    {
    }
}

答案 1 :(得分:0)

“尝试读取或写入受保护的内存”通常意味着您有一个超出范围的垃圾指针或指针算法。垃圾指针也可能导致应用程序挂起或崩溃难以重现。

要回答您的线程问题,最简单的解决方案IMO是使用.NET 4.0 Tasks而不是线程。可以使用取消令牌构建任务。您的主线程可以使用该取消令牌来通知任务线程是时候关闭商店并回家了。