【问题标题】:Variation on thread locking线程锁定的变化
【发布时间】:2013-12-11 08:00:36
【问题描述】:

我正在编写一个同时运行多个请求的网络抓取程序。但是,有些请求需要连续发生,所以我的第一个想法是对需要一起发生的两个请求加锁,并在其他请求周围加锁。这种方法的问题是其他两个请求会相互锁定,但可以并行运行。

例如,我需要网站上有四个页面的数据:

  • example.com/page1
  • example.com/page2
  • example.com/page3
  • example.com/page4

当程序启动时,我启动了三个线程:一个用于 page1,一个用于 page2 和 page 3,一个用于 page4。 page3 的请求必须在 page2 的请求之后直接发生。 page1 和 page4 的请求可以同时发生。

如果我不使用锁定,可能会在请求 page2 和 page3 之间请求 page1 或 page4 并导致问题。如果我对三个线程使用相同的锁,那么对 page1 的请求可能会阻塞对 page4 的请求。

如何防止在 page2 和 page3 之间发生请求,但允许其他请求同时发生?

【问题讨论】:

  • 强制性警告:如果您非常关心东西运行的顺序,那么线程可能是错误的答案。您试图名义上并行运行一些东西,然后强制它串行运行——这违背了整个目的。
  • "对 page2 的请求必须发生在对 page2 的请求之后。" - 目前这个错字(不管是什么)使这个问题很难理解。
  • @cHao,根据工作是什么,创建和启动线程可能是我们的优势,因此它们可以,例如,进行一些初始化,然后等待触发。如果为线程准备数据和创建线程并行运行,这可能会特别节省时间。
  • @cHao,我关心一些请求的顺序,而不是整个请求。
  • 为什么不简单地在同一个线程上按正确的顺序执行第 2 页和第 3 页?

标签: c# multithreading locking


【解决方案1】:

您可以尝试使用信号量来控制对“页面请求”伪资源的访问。可以并发运行的请求只需要一个资源,必须以独占方式运行的请求需要所有资源。

类似于以下内容:

private static Semaphore _pool;
private static readonly int kMaxConcurrrentPageRequesters = 4;  // or whatever number

// at some appropriate initialization point

_pool = new Semaphore(kMaxConcurrrentPageRequesters,kMaxConcurrrentPageRequesters);


// when a normal request is being made that can run concurrently:

_pool.WaitOne();
perform_page_request();
_pool.Release();


// when an exclusive page request is being made:

// maybe create a Semaphore wrapper that stores the max semaphore count
//   so that you can expose a `WaitAll()` method to replace this loop
for (int i = 0; i < kMaxConcurrrentPageRequesters; ++i) {
    _pool.WaitOne();
}
perform_exclusive_page_requests();
_pool.Release(kMaxConcurrrentPageRequesters);

【讨论】:

  • 我会试一试。谢谢!
  • 如果多个线程同时尝试exclusive_page_request,可能会死锁,但也许这不是问题。
  • @MartinJames:好点——至少目前,我会为读者留下一个解决方案。我怀疑解决方案可能不是微不足道的。所以现在这个答案只有在只有一个线程可能需要独占访问时才是安全的。
【解决方案2】:

您可以延迟线程的执行或让它们等待。例如,

var waitA = false;
var thread1 = new Thread((Action)(() => { while(!waitA) Thread.Sleep(0); /* do work here */ })).Start();
var thread2 = new Thread((Action)(() => { while(!waitA) Thread.Sleep(0); /* do work here */ })).Start();
// prepare data for threads? and start them
waitA = true;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-02
    相关资源
    最近更新 更多