我在C#4.0中实现一个漫画阅读器,并从一个图像浏览 由于我实施了一些流程,下一段时间需要一些时间。
因此,我以UI线程将显示的方式实现它 首先是后台线程正在处理的未处理图像 图像,稍后将替换未处理的图像。
一切正常但现在,有些用户会疯狂地想点击下一步 图像连续,这导致后台工作程序进行处理 所有这些点击并显示所有图像。
我想要的是:如果用户多次点击,我想要背景 worker只处理最后一个线程。
我做了什么:现在,我已经实现了一个功能来检查 活动线程数,如果活动线程大于1, 后台线程不会处理但返回上一个图像(那个 不好,因为未经处理的图像将是前面的一个索引)
如果您有意,请像初学者一样向我解释!
private void button4_Click(object sender, EventArgs e)
{
Bitmap b = new Bitmap(this.CurrImage);
if (!shutdown)
{
process_updateThread = new Thread(new ThreadStart(process_update));
process_updateThread.Start();
}
pictureBox1.Image = b; //image will be replaced by worker thread image
pictureBox1.Location = ImageEdit.CalculateLocationImage(b);
SetBackColor(b);
ShowPageCount();
updateNavButtons();
}
void StopThread()
{
if(((IEnumerable)System.Diagnostics.Process.GetCurrentProcess().Threads).OfType<System.Diagnostics.ProcessThread>()
.Where(t => t.ThreadState == System.Diagnostics.ThreadState.Running).Count() > 1)
shutdown = true;
else shutdown = false;
}
答案 0 :(得分:0)
我假设您的长时间运行过程是process_update。
您必须在运行下一个process_updates之前停止所有正在运行的process_updates。但是不要使用BOOLEAN VARIABLE去做 !!!您必须使用同步对象。最有可能的是它应该是ManualResetEvent。
更新:
这个非常简单的示例可以让您了解多线程和线程管理
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsExamples
{
public partial class OnlyOneThread : Form
{
List<ManualResetEvent> threadStopEvents; //This will hold stop events for running threads
public OnlyOneThread()
{
InitializeComponent();
threadStopEvents = new List<ManualResetEvent>();
}
private void runThreadBtn_Click(object sender, EventArgs e)
{
ManualResetEvent evt = new ManualResetEvent(false);
ParameterizedThreadStart ts = new ParameterizedThreadStart(this.ThreadFunc);
Thread t = new Thread(ts);
t.Start(evt);
}
private delegate void UptadeThreadCountDelegate(); //This delegate is used by Invoke method
private void UpdateThreadCount()
{
threadcountLbl.Text = threadStopEvents.Count.ToString();
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
//We must stop threads if they are still running
lock (threadStopEvents) // locking prevents simultaneous list access
{
foreach (ManualResetEvent evt in threadStopEvents)
{
evt.Set(); //signal all events
}
}
}
//This is thread function
private void ThreadFunc(Object obj)
{
ManualResetEvent stopEvent = obj as ManualResetEvent; //cast an object that was passed by Thread.Start()
lock (threadStopEvents) // locking prevents simultaneous list access
{
foreach (ManualResetEvent evt in threadStopEvents)
{
evt.Set(); //signal all events for all other threads to stop
}
threadStopEvents.Add(stopEvent); //Put our event on list
}
if (this.IsHandleCreated) // This is necessary for invocation
this.Invoke(new UptadeThreadCountDelegate(this.UpdateThreadCount)); //Invoke counter update
for (int i = 0; i < 60; i++) // this will run about 1 minute
{
if (stopEvent.WaitOne(0)) // Tests stopEvent and continues
{
//Stop signaled!!! exit!
break;
}
Thread.Sleep(1000); //Sleep 1 second
}
lock (threadStopEvents) // locking prevents simultaneous list access
{
threadStopEvents.Remove(stopEvent); //remove stop event from list
}
if (this.IsHandleCreated) // This is necessary for invocation
this.Invoke(new UptadeThreadCountDelegate(this.UpdateThreadCount)); //Invoke counter update
}
}
}
如果要运行此示例,则必须创建WindowsForms项目并在表单上添加Button和label,然后使用此代码绑定到这些控件。注意一下form方法的调用。当来自非GUI线程时,这是必要的。
答案 1 :(得分:0)
我看不出这个问题的简单解决方案......多线程绝非易事。就个人而言,我建议遵循(生产者/消费者情况的一种偏差):
一个很好地锁定的ImageMonitor,它有一个方法:
现在我们需要一个连续工作的后台线程,它循环并在每次迭代中检查ImageMonitor以处理最新图像,处理图像并将其返回给ImageMonitor(包括计数器)
当ImageMonitor从背景渲染器获取渲染图像时,它可以检查图像是否具有正确的计数器值,如果是,那么它可以将当前图像与渲染图像交换
这个解决方案显然有点复杂。但是,它应该工作。我对其他(更简单的)解决方案感兴趣。
祝你好运