线程作业分配正确性

时间:2013-07-02 03:10:10

标签: multithreading thread-safety

假设我有一堆工作线程,我想避免线程确定谁得到什么工作的时间。

假设每个线程都有一个与之关联的编号/ ID。有一份工作清单。队列中的每个作业都有一个与之关联的ThreadID。

ThreadID
1          = Job Available
0          = Job Finished
> 1        = Active ==> ThreadID = ID of thread working on the job

对于要在作业上工作的线程,它会扫描列表并找到第一个ThreadID = 1并尝试接受该作业。

这样线程就会消耗工作。 (显然他们会睡觉,需要被正确地吵醒,但现在却忽略了所有这些)

问题是,两个线程可能同时尝试在同一个作业上工作,这很糟糕。

要解决这个问题,每个线程只需将其线程ID分配给线程ID,这将阻止其他线程在作业上工作,除非读取一个线程ID在写入线程ID之前。

ThreadID      Thread 11         Thread 12            ....
1             ThreadID == 1?                         Job available
                                ThreadID == 1?       Job available
11            ThreadID = 11                          Try to take job
12                              ThreadID == 12       Try to take job
              ThreadID == 11?                        Job was taken by another thread
                                ThreadID == 12?      (If no other competing threads then thread 12 got the job)

不确定该表是否有意义,但它显示了两个竞争该作业的线程。他们都认为他们有工作但是ThreadId中的任何一个线程确实有他们的数字得到了工作(它将是写入ThreadID的最后一个线程)。

我相信这样的方案不需要锁并且安全吗?这是对的吗?

2 个答案:

答案 0 :(得分:1)

通常,当您拥有一组作业和多个线程来处理作业时,您可以通过锁定或通过更复杂的非阻塞机制将作业放入线程安全队列中,例如ConcurrentQueue<T> in .NET 4。

每个线程从队列中获取一个作业并对其进行处理。如果线程无法完全处理它,您需要一些机制来在队列中作业。

但是,如果您想继续将作业标记为由线程处理的方法,则执行此操作非常简单,但您需要使用锁定以确保一次只有一个线程修改作业。

答案 1 :(得分:0)

我认为你所描述的“比较 - 写入 - 比较”方法是不够的。看这个案例:

  Thread 0          Thread 1

reads <empty>
                  reads <empty> 
writes 0
reads 0
runs task
                  writes 1
                  reads 1
                  runs task

交错将使两个线程执行相同的任务。我可能在你的描述中遗漏了一些东西,但如果我理解你的算法,那么这应该是它的健全性的矛盾。