C# Winforms中的两个线程任务持续检查
我目前正试图在本地文件夹的C#上为创建的新文件保留一个计数器 我有两个子目录的CD和LP,我必须不断检查。使用计数器,确保创建的文件夹计数未超过用户设置的计数C# Winforms中的两个线程任务持续检查,c#,multithreading,C#,Multithreading,我目前正试图在本地文件夹的C#上为创建的新文件保留一个计数器 我有两个子目录的CD和LP,我必须不断检查。使用计数器,确保创建的文件夹计数未超过用户设置的计数 public static int LPmax { get; set; } public static int CDmax { get; set; } public static int LPcounter2 { get; set; } public static int CDcounter2 { get; set; } publi
public static int LPmax { get; set; }
public static int CDmax { get; set; }
public static int LPcounter2 { get; set; }
public static int CDcounter2 { get; set; }
public static int LPCreated;
public static int CDCreated;
public static int oldLPCreated;
public static int oldCDCreated;
FileSystemWatcher CDdirWatcher = new FileSystemWatcher();
FileSystemWatcher LPdirWatcher = new FileSystemWatcher();
上面的方法工作得很好,标准是它必须少于一组
public void checker()
{
if(CDCreated>CDmax)
{
popupbx();
}
if(LPCreated>LPmax)
{
popupbx();
}
}
问题是我的主要方法,我有两个线程需要不断检查这两个标准,看看是否超过了计数器
public Form1()
{
InitializeComponent();
//Implementing Threads asynchronously
Thread oThreadone = new Thread(() =>
{
//Do what u wanna……
watch();
});
Thread oThreadtwo = new Thread(() =>
{
//Do what u wanna……
checker();
});
//Calling thread workers
oThreadone.Start();
oThreadone.IsBackground = true;
oThreadtwo.Start();
oThreadtwo.IsBackground = true;
}
Mkdir在调试模式下触发计数器,但线程二在触发计数器后不检查计数器。代码的第一个主要错误是,您创建的线程都不需要,也不做您想做的事情。具体来说,
FileSystemWatcher
对象本身已经是异步的,因此您可以在主线程中创建它。事实上,您应该这样做,因为您可以将FileSystemWatcher.SynchronizingObject
设置为当前表单实例,以便它在该对象的同步上下文中引发其事件。也就是说,您的事件处理程序将在主线程中执行,这是您想要的
因此,第一个方法,watch()
,不是在线程中执行,而是直接调用它
这就引出了第二种方法,checker()
。线程的方法不会循环,因此它将执行两个测试,然后立即退出。这就是那条线的尽头。它不会停留足够长的时间来监控更新后的计数
您可以通过在checker()
方法中循环来修复它,这样它就永远不会退出。但是你会遇到CPU使用过度的问题。您将通过添加sleep语句来修复此问题。那你大部分时间都在浪费一个线程。您可以使用async
/await
(例如await Task.Delay()
)修复此问题。但这会使代码变得不必要的复杂
相反,您应该在更新每个计数后执行每个检查。理论上,您可以立即显示消息。但这将阻止订阅FileSystemWatcher
的事件处理程序,可能会延迟其他报告。因此,您可能更愿意使用Control.BeginInvoke()
将消息的显示推迟到事件处理程序返回之后
因此,考虑到所有这些因素,您的代码可能更像这样:
public Form1()
{
初始化组件();
手表();
}
已创建私有void CDdirWatcher_(对象发送方、文件系统目标)
{
CDCreated+=1;
如果(CDCreated>CDmax)
{
BeginInvoke((MethodInvoker)PopupBox);
}
}
已创建私有静态无效LPdirWatcher_(对象发送方、文件系统目标)
{
lp+=1;
如果(LPCreated>LPmax)
{
BeginInvoke((MethodInvoker)PopupBox);
}
}
您可以完全删除checker()
方法。watch()
方法可以保持原样,不过我会更改订阅创建的事件的顺序以及EnableRaisingEvents
的分配。也就是说,在订阅活动之前,不要启用筹款活动。FileSystemWatcher
已经足够不可靠了,如果您没有在准备观察事件之前给它一个引发事件的机会的话。:)
这是基于您当前的实现。请注意,如果不断创建文件,则消息将反复显示。如果创建速度足够快,则在用户可以关闭以前显示的消息之前,将显示新消息。您可能希望修改代码以防止出现这种情况。例如,在您已超过最大计数后取消订阅活动,或至少在已显示一条此类消息时暂时禁止显示消息。具体做什么取决于你,超出了你的问题范围,也超出了这个答案的范围。那么“问题”是什么?至少,代码应该在UI线程上封送UI操作。。请参阅此处使用的关键字。此外,使用线程似乎有问题:没有什么可循环的。文件监视程序已经异步运行了。我真的认为我的第一个方法需要一个后台线程,因为它需要持续运行并检查新文件夹的创建,也许计数器不需要在线程中。但我真的不太确定Filewatcher是否通过异步回调提供信息,就像“按钮点击”事件一样。它在内部使用线程(或其他并发方法)。不需要不断地重新创建它(即在循环中),也不需要调用任何阻塞方法来确保它的执行。是的,这可能不是一个很好的用法\项目来学习线程-因为您使用的类型没有像这样被正确使用;话虽如此,这里的答案真的应该是为了解决问题和期望。我的应用程序是否仍有可能在达到限制后在后台显示弹出窗口?作为旁注,在设置。EnableRaisingEvents=true代码>。另外,在/block中初始化FSW对象也是非常可取的,尤其是在表单的构造函数中创建FSW对象时,或者在引发Form.Load事件之前创建FSW对象时。
public Form1()
{
InitializeComponent();
//Implementing Threads asynchronously
Thread oThreadone = new Thread(() =>
{
//Do what u wanna……
watch();
});
Thread oThreadtwo = new Thread(() =>
{
//Do what u wanna……
checker();
});
//Calling thread workers
oThreadone.Start();
oThreadone.IsBackground = true;
oThreadtwo.Start();
oThreadtwo.IsBackground = true;
}