C# C石英赛道条件

C# C石英赛道条件,c#,multithreading,quartz.net,race-condition,C#,Multithreading,Quartz.net,Race Condition,我正在自动化我的网站上的一些任务,但我目前被卡住了 public void Execute(JobExecutionContext context) { var linqFindAccount = from Account in MainAccounts where Account.Done == false select

我正在自动化我的网站上的一些任务,但我目前被卡住了

    public void Execute(JobExecutionContext context)
    {
            var linqFindAccount = from Account in MainAccounts
                                  where Account.Done == false
                                  select Account;

            foreach (var acc in linqFindAccount)
            {
                acc.Done = true;
                // stuff
            }
     }
问题是,当我启动多个线程时,第一个线程被分配到同一个第一个帐户,因为它们同时将Done值设置为true。我该如何避免这种情况

编辑:

前两个线程被分配给第一个帐户,即使列表中包含30个帐户

谢谢。

使用

private static readonly object locker = new object();
而不是

private  object locker = new object();

您的问题是,延迟执行发生在启动foreach循环时。因此,结果被缓存,而不是在每个循环中重新计算。所以每个线程都将使用它自己的项目列表。因此,当一个帐户设置为“完成”时,另一个列表中的对象仍然保留


在这种情况下,队列更合适。只需将项目放入共享队列中,让循环获取队列中的项目,并在队列为空时让它们结束。

代码中存在一些问题:

1假设您使用无状态Quartz作业,那么您的锁没有任何用处。Quartz每次触发触发器时都会创建新的作业实例。这就是为什么您会看到同一个帐户被处理了两次。只有使用statefuljob和statefuljob时,它才会起作用。或者将锁设为静态,但请继续阅读

2即使1是固定的,它也无法达到拥有多个线程的目的,因为它们都将在同一个锁上等待对方。您最好有一个线程来执行此操作

我对需求了解不够,尤其是//方面的情况。也许您不需要在多个线程上运行此代码,顺序执行就可以了。我假设情况并非如此,您希望多线程运行它。最简单的方法是只做一份工作。在这个作业中,分块加载帐户,比如说每个块中有100个作业。如果你有500个帐户,这将给你5块。将每个块处理卸载到。它将考虑使用最佳线程数。这将是一个穷人的生产者消费者队列

public void Execute(JobExecutionContext context) {

    var linqFindAccount = from Account in MainAccounts
                            where Account.Done == false
                            select Account;
    IList<IList<Account>> chunks = linqFindAccount.SplitIntoChunks(/* TODO */);

    foreach (IList<Account> chunk in chunks) {
        ThreadPool.QueueUserWorkItem(DoStuff, chunk);
    }
}

private static void DoStuff(Object parameter) {
    IList<Account> chunk = (IList<Account>) parameter;

    foreach (Account account in chunk) {
        // stuff
    }
}
通常,对于多线程,在访问可变共享状态时必须非常小心。您必须确保在“DoStuff”方法中所做的一切不会导致不希望的副作用。你可能会发现它很有用


试试上面的方法。

您能详细介绍一下shoydl到底使用了什么执行方法吗?是否只更新已找到帐户的“完成”属性?为什么需要多个线程?您将需要某种类型的锁对象。请参阅可能更好的链接,但这是我发现的第一个@sllev I更新已完成帐户的done属性,问题是我同时启动了约20个线程,并且前2-3个线程被分配给同一个第一帐户,因为它们同时启动,同时done值设置为false,我需要多个线程,因为它更快。枚举列表和设置属性的多个线程更快?到底什么更快?我建议坚持单身thread@sllev显然,您错过了//stuff注释。我做的更多,因此多个线程更快,因为多个帐户同时完成。这个链接可能有用,在这种情况下我们不需要多线程
public void Execute(JobExecutionContext context) {

    var linqFindAccount = from Account in MainAccounts
                            where Account.Done == false
                            select Account;
    IList<IList<Account>> chunks = linqFindAccount.SplitIntoChunks(/* TODO */);

    foreach (IList<Account> chunk in chunks) {
        ThreadPool.QueueUserWorkItem(DoStuff, chunk);
    }
}

private static void DoStuff(Object parameter) {
    IList<Account> chunk = (IList<Account>) parameter;

    foreach (Account account in chunk) {
        // stuff
    }
}
 foreach (var acc in linqFindAccount)
        {
            string mailComponent = acc.Mail;
            Console.WriteLine(context.JobDetail.Name + " assigned to " + mailComponent);
            acc.Done = true;
            // stuff
        }