我是线程的新手,所以我不确定我是否做正确的事,但会很感激。当用户单击鼠标时,我有以下代码运行;它基本上运行了一些路径调查代码并移动播放器。
但是,我的问题是当我在线程运行时再次单击鼠标时,会引起问题。有没有办法停止上一个线程并在第二次到达该代码时启动新线程?
private void checkMouse()
{
mouseCommand mc = new mouseCommand();
Thread oThread = new Thread(() => mc.leftClick(Mouse.GetState().X,Mouse.GetState().Y));
oThread.Start();
}
也许类似的东西对您有用吗?
private object lock_object - new object();
private Thread oThread = new Thread();
private void checkMouse()
{
lock(lock_object)
{
if (oThread.ThreadState != ThreadState.Running)
{
mouseCommand mc = new mouseCommand();
oThread = new Thread(() => mc.leftClick(Mouse.GetState().X,Mouse.GetState().Y));
oThread.Start();
}
}
}
有几种方法可以做到这一点。
最简单的,当学习线程时,您应该第一次了解锁定。有一个object
,您用来锁定此问题以及如果它们在一起发生的任何相关操作也会引起问题:
private object lockObj = new object();
private static void DoLClick()
{
lock(lockObj)
{
mouseCommand mc = new mouseCommand();
mc.leftClick(Mouse.GetState().X,Mouse.GetState().Y));
}
}
private void checkMouse()
{
Thread oThread = new Thread(DoLClick);
oThread.Start();
}
好处是,这可以防止线程互相脚趾。
缺点是丧失并发性(所有这些线程都相互等待,而不是做某事)和僵局的风险(如果线程A有锁定1,并且需要锁定2,则螺纹B具有锁定2,并且需要锁定锁1,你卡住了)。
它仍然是最简单的方法。通常,即使您需要使用另一种方法,也值得从定义广泛的锁开始,然后更改为较窄的锁(也就是说,锁定较少的代码)或以后的其他方法。
>另一种可能性是有锁,但是您不使用lock(){}
来获得它,而是使用time-ut-Out(也许为零)的Monitor.TryEnter()
,如果您不明白,请放弃:
private object lockObj = new object();
private static void DoLClick()
{
if(!Monitor.TryEnter(lockObj, 0))
return; // Just do nothing if we're busy.
try
{
mouseCommand mc = new mouseCommand();
mc.leftClick(Mouse.GetState().X,Mouse.GetState().Y));
}
finally
{
Monitor.Exit(lockObj);
}
}
private void checkMouse()
{
Thread oThread = new Thread(DoLClick);
oThread.Start();
}
缺点是您无法完成第二个任务。好处是,如果已经完成了,您通常不想做某事,并且您可以免费获得。
其他一些方法是其中的一种变体,其中您是描述要执行任务的线程安全对象;它可能是需要执行的操作的整数计数,您使用Interlocked.Increment()
和Interlocked.Decrement()
进行更改,或者是描述需要执行任务的对象的ConcurrentQueue
。然后,您可以将线程未能添加到该线程,并且确实使锁定的线程接管了该线程的工作。或者,您也许可能会有一个专用线程,只需继续寻找工作,并且每当工作用尽时等待AutoResetEvent
-允许它工作的线程(添加到队列)设置该事件以确保它不仅坐着坐着。什么都没有。
所有这些可能性(以及更多)值得学习并拥有它们的位置,但是lock
的第一个建议是第一个学习的建议。