运行线程时 Windows 窗体挂起

发布于 2024-08-24 14:26:03 字数 4603 浏览 7 评论 0原文

JI 在 Visual Studio 2008 中编写了一个 .NET C# Windows 窗体应用程序,该应用程序使用信号量在按下“开始”按钮时将多个作业作为线程运行。

它遇到了一个问题,即表单在运行 40 分钟或更长时间后变成逗号。日志文件表明当前作业已完成,它从列表中选择一个新作业,然后挂起。

我注意到,发生这种情况时,Windows 窗体会变得无响应。该表单在其自己的线程中运行。

这是我正在使用的代码示例:

protected void ProcessJobsWithStatus (Status status)
        {
int maxJobThreads = Convert.ToInt32(ConfigurationManager.AppSettings["MaxJobThreads"]);
            Semaphore semaphore = new Semaphore(maxJobThreads, maxJobThreads);  // Available=3; Capacity=3


            int threadTimeOut = Convert.ToInt32(ConfigurationManager.AppSettings["ThreadSemaphoreWait"]);//in Seconds
            //gets a list of jobs from a DB Query.
List<Job> jobList = jobQueue.GetJobsWithStatus(status);
            //we need to create a list of threads to check if they all have stopped.
            List<Thread> threadList = new List<Thread>();
            if (jobList.Count > 0)
            {
                foreach (Job job in jobList)
                {
                    logger.DebugFormat("Waiting green light for JobId: [{0}]", job.JobId.ToString());
                    if (!semaphore.WaitOne(threadTimeOut * 1000))
                    {
                        logger.ErrorFormat("Semaphore Timeout. A thread did NOT complete in time[{0} seconds]. JobId: [{1}] will start", threadTimeOut, job.JobId.ToString());

                    }

                    logger.DebugFormat("Acquired green light for JobId: [{0}]", job.JobId.ToString());
                    // Only N threads can get here at once    
                    job.semaphore = semaphore;
                    ThreadStart threadStart = new ThreadStart(job.Process);

                    Thread thread = new Thread(threadStart);
                    thread.Name = job.JobId.ToString();
                    threadList.Add(thread);
                    thread.Start();


                }

                logger.Info("Waiting for all threads to complete");

                //check that all threads have completed.
                foreach (Thread thread in threadList)
                {
                    logger.DebugFormat("About to join thread(jobId): {0}", thread.Name);
                    if (!thread.Join(threadTimeOut * 1000))
                    {
                        logger.ErrorFormat("Thread did NOT complete in time[{0} seconds]. JobId: [{1}]", threadTimeOut, thread.Name);
                    }
                    else {
                        logger.DebugFormat("Thread did complete in time. JobId: [{0}]", thread.Name);
                    }
                }                   

            }

            logger.InfoFormat("Finished Processing Jobs in Queue with status [{0}]...", status);

}

//formmethods

private void button1_Click(object sender, EventArgs e)
        {
            buttonStop.Enabled = true;
            buttonStart.Enabled = false;

            ThreadStart threadStart = new ThreadStart(DoWork);
            workerThread = new Thread(threadStart);

            serviceStarted = true;
            workerThread.Start();



        }

private void DoWork()
        {
            EmailAlert emailAlert = new EmailAlert ();
            // start an endless loop; loop will abort only when "serviceStarted" flag = false
            while (serviceStarted)
            {  
                emailAlert.ProcessJobsWithStatus(0);

                // yield
                if (serviceStarted)
                {
                    Thread.Sleep(new TimeSpan(0, 0, 1));
                }
            }

            // time to end the thread
            Thread.CurrentThread.Abort();
        }

//job.process()

 public void Process()
        {
             try
            {

                //sets the status, DateTimeStarted, and the processId
                this.UpdateStatus(Status.InProgress);

                //do something

                logger.Debug("Updating Status to [Completed]");

                //hits, status,DateFinished
                this.UpdateStatus(Status.Completed);

            }
            catch (Exception e)
            {
                logger.Error("Exception: " + e.Message);
                this.UpdateStatus(Status.Error);

            }
            finally {
                logger.Debug("Relasing semaphore");
                semaphore.Release();
            }

我尝试将我能记录到的文件中以检测问题发生的位置,但到目前为止我还无法以确定发生这种情况的位置。失去对 Windows 窗体的控制让我认为这与处理作业无关。有什么想法吗?

解决方案:使用 RedGate ANTS 对其进行分析会产生该问题。直接运行时不会发生这种情况。

JI have written a .NET C# Windows Form app in Visual Studio 2008 that uses a Semaphore to run multiple jobs as threads when the Start button is pressed.

It’s experiencing an issue where the Form goes into a comma after being run for 40 minutes or more. The log files indicate that the current jobs complete, it picks a new job from the list, and there it hangs.

I have noticed that the Windows Form becomes unresponsive when this happens. The form is running in its own thread.

This is a sample of the code I am using:

protected void ProcessJobsWithStatus (Status status)
        {
int maxJobThreads = Convert.ToInt32(ConfigurationManager.AppSettings["MaxJobThreads"]);
            Semaphore semaphore = new Semaphore(maxJobThreads, maxJobThreads);  // Available=3; Capacity=3


            int threadTimeOut = Convert.ToInt32(ConfigurationManager.AppSettings["ThreadSemaphoreWait"]);//in Seconds
            //gets a list of jobs from a DB Query.
List<Job> jobList = jobQueue.GetJobsWithStatus(status);
            //we need to create a list of threads to check if they all have stopped.
            List<Thread> threadList = new List<Thread>();
            if (jobList.Count > 0)
            {
                foreach (Job job in jobList)
                {
                    logger.DebugFormat("Waiting green light for JobId: [{0}]", job.JobId.ToString());
                    if (!semaphore.WaitOne(threadTimeOut * 1000))
                    {
                        logger.ErrorFormat("Semaphore Timeout. A thread did NOT complete in time[{0} seconds]. JobId: [{1}] will start", threadTimeOut, job.JobId.ToString());

                    }

                    logger.DebugFormat("Acquired green light for JobId: [{0}]", job.JobId.ToString());
                    // Only N threads can get here at once    
                    job.semaphore = semaphore;
                    ThreadStart threadStart = new ThreadStart(job.Process);

                    Thread thread = new Thread(threadStart);
                    thread.Name = job.JobId.ToString();
                    threadList.Add(thread);
                    thread.Start();


                }

                logger.Info("Waiting for all threads to complete");

                //check that all threads have completed.
                foreach (Thread thread in threadList)
                {
                    logger.DebugFormat("About to join thread(jobId): {0}", thread.Name);
                    if (!thread.Join(threadTimeOut * 1000))
                    {
                        logger.ErrorFormat("Thread did NOT complete in time[{0} seconds]. JobId: [{1}]", threadTimeOut, thread.Name);
                    }
                    else {
                        logger.DebugFormat("Thread did complete in time. JobId: [{0}]", thread.Name);
                    }
                }                   

            }

            logger.InfoFormat("Finished Processing Jobs in Queue with status [{0}]...", status);

}

//form methods

private void button1_Click(object sender, EventArgs e)
        {
            buttonStop.Enabled = true;
            buttonStart.Enabled = false;

            ThreadStart threadStart = new ThreadStart(DoWork);
            workerThread = new Thread(threadStart);

            serviceStarted = true;
            workerThread.Start();



        }

private void DoWork()
        {
            EmailAlert emailAlert = new EmailAlert ();
            // start an endless loop; loop will abort only when "serviceStarted" flag = false
            while (serviceStarted)
            {  
                emailAlert.ProcessJobsWithStatus(0);

                // yield
                if (serviceStarted)
                {
                    Thread.Sleep(new TimeSpan(0, 0, 1));
                }
            }

            // time to end the thread
            Thread.CurrentThread.Abort();
        }

//job.process()

 public void Process()
        {
             try
            {

                //sets the status, DateTimeStarted, and the processId
                this.UpdateStatus(Status.InProgress);

                //do something

                logger.Debug("Updating Status to [Completed]");

                //hits, status,DateFinished
                this.UpdateStatus(Status.Completed);

            }
            catch (Exception e)
            {
                logger.Error("Exception: " + e.Message);
                this.UpdateStatus(Status.Error);

            }
            finally {
                logger.Debug("Relasing semaphore");
                semaphore.Release();
            }

I have tried to log what I can into a file to detect where the problem is happening, but so far I haven't been able to identify where this happens. Losing control of the Windows Form makes me think that this has nothing to do with processing the jobs. Any ideas?

Solution: Profiling it with RedGate ANTS was producing the issue. It does not happen when run directly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

爱你不解释 2024-08-31 14:26:03

我看到的第一件事是您的 Thread.CurrentThread.Abort() 调用。这是不必要的。让函数退出,线程就会正常关闭。

我注意到的第二件事是,即使获取信号量发生超时,线程仍然会被创建。您的表单可能由于线程过多而挂起。

logger.DebugFormat("Waiting green light for JobId: [{0}]", job.JobId.ToString());
if (!semaphore.WaitOne(threadTimeOut * 1000))
{
   logger.ErrorFormat("Semaphore Timeout. A thread did NOT complete in time[{0} seconds]. JobId: [{1}] will start", threadTimeOut, job.JobId.ToString());
   // Should have exit here.
}
logger.DebugFormat("Acquired green light for JobId: [{0}]", job.JobId.ToString());

第三件事是您的工作线程正在调用一个函数,该函数只是为作业循环中的每个作业创建线程。如果一个作业没有完成(假设这会导致一个作业从队列中删除,因为我在任何地方都看不到该代码。)在 DoWork 从睡眠中醒来之前,它将迭代同一个作业并尝试创建另一个作业线程为它。

The first thing I see is your Thread.CurrentThread.Abort() call. This is unnecessary. Let the function exit and the thread will shut down gracefully.

The second thing I noticed is that even if a timeout occurs for acquiring a semaphore a thread will be created anyway. Your form could be hanging as a result of too many threads.

logger.DebugFormat("Waiting green light for JobId: [{0}]", job.JobId.ToString());
if (!semaphore.WaitOne(threadTimeOut * 1000))
{
   logger.ErrorFormat("Semaphore Timeout. A thread did NOT complete in time[{0} seconds]. JobId: [{1}] will start", threadTimeOut, job.JobId.ToString());
   // Should have exit here.
}
logger.DebugFormat("Acquired green light for JobId: [{0}]", job.JobId.ToString());

The third thing is your worker thread is calling a function which simply creates threads for every job in the jobs loop. If a job doesn't complete (assuming this causes a job to be removed from the queue since I don't see that code anywhere.) before DoWork wakes up from it's sleep it's going to iterate over the same Job and try to create another thread for it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文