C# Winforms中的两个线程任务持续检查

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

我目前正试图在本地文件夹的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; } 

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