运行线程时 Windows 窗体挂起
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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我看到的第一件事是您的 Thread.CurrentThread.Abort() 调用。这是不必要的。让函数退出,线程就会正常关闭。
我注意到的第二件事是,即使获取信号量发生超时,线程仍然会被创建。您的表单可能由于线程过多而挂起。
第三件事是您的工作线程正在调用一个函数,该函数只是为作业循环中的每个作业创建线程。如果一个作业没有完成(假设这会导致一个作业从队列中删除,因为我在任何地方都看不到该代码。)在 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.
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.