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);

}

//形成方法

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 对其进行分析会产生问题。直接运行时不会发生。

4

1 回答 1

3

我看到的第一件事就是你的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 从睡眠中唤醒之前,它将迭代同一个作业并尝试创建另一个线程。

于 2010-03-11T16:43:36.680 回答