Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 信号量不';t似乎无法处理多个线程_C#_Multithreading_.net 3.5 - Fatal编程技术网

C# 信号量不';t似乎无法处理多个线程

C# 信号量不';t似乎无法处理多个线程,c#,multithreading,.net-3.5,C#,Multithreading,.net 3.5,我希望同时运行多个线程(例如,最多5个线程),当其中一个线程完成时,新线程将以不同的数据启动。(一次完成,一次新开始,两次完成,两次新开始… Main for循环采用Main形式,但从不同的线程运行,不会阻塞UI 当我运行它时,程序会添加5个web浏览器控件(作为视觉进度),当页面加载完成时,它会删除加载的控件。 问题是表单中没有添加更多控件。 也许信号量没有被正确地释放以允许新的信号量启动,或者我遗漏了什么 如果我关闭程序,它不会退出,我想它会被WaitHandle.WaitOne阻止,因为还

我希望同时运行多个线程(例如,最多5个线程),当其中一个线程完成时,新线程将以不同的数据启动。(一次完成,一次新开始,两次完成,两次新开始…
Main for循环采用Main形式,但从不同的线程运行,不会阻塞UI

当我运行它时,程序会添加5个web浏览器控件(作为视觉进度),当页面加载完成时,它会删除加载的控件。
问题是表单中没有添加更多控件。
也许信号量没有被正确地释放以允许新的信号量启动,或者我遗漏了什么

如果我关闭程序,它不会退出,我想它会被WaitHandle.WaitOne阻止,因为还有更多的工作要做

为了代码更清晰,我删除了一些不需要的数据

Semaphore pool = new Semaphore(5, 5);
Scraper[] scraper = new Scraper[5];
Gecko.GeckoWebBrowser wb = null;
int j = 0;
for (int i = 0; i < arrScrapeboxItems.Count; i++)
{
    pool.WaitOne();
    bool pustiMe = true;
    while (pustiMe)
    {
        if (scraper[j] == null) scraper[j] = new Scraper();
        if (scraper[j].tred == null)
        {
            ScrapeBoxItems sbi = (ScrapeBoxItems)arrScrapeboxItems[i];

            doneEvents.Add(new ManualResetEvent(false)); // this is for WaitHandle.WaitAll after the for loop is done all the items

            wb = new Gecko.GeckoWebBrowser();
            PoolObjects po = new PoolObjects();
            po.link = sbi.link;
            // etc...

            scraper[j].ThreadsCompleted += new Scraper.ThreadsHandler(frmMain_NextThreadItemsCompleted);
            scraper[j].tred = new Thread(new ParameterizedThreadStart(scraper[j].Scrape));
            scraper[j].tred.Start(po);

            pustiMe = false;
            if (j == maxThreads - 1)
                j = 0;
            else
                j++;
            break;
        }
        else if (scraper[j].tred.IsAlive) // if the thread is finished, make room for new thread
        {
            scraper[j] = null;
        }
        if (pustiMe) Thread.Sleep(1000);
    }
}

// event from Scraper class
void frmMain_ThreadsCompleted()
{
    pool.Release();
}
信号量池=新信号量(5,5);
刮刀[]刮刀=新刮刀[5];
Gecko.GeckoWebBrowser wb=null;
int j=0;
对于(int i=0;i
刮刀类看起来像:

public void Scrape(object o)
{
    po = (PoolObjects)o;
    // do stuff with po

    po.form.Invoke((MethodInvoker)delegate
    {
        po.form.Controls.Add(po.wb);
        po.wb.DocumentCompleted += new EventHandler<Gecko.Events.GeckoDocumentCompletedEventArgs>(wb_DocumentCompleted);
        po.wb.Navigate(po.link);
    });
}

void wb_DocumentCompleted(object sender, Gecko.Events.GeckoDocumentCompletedEventArgs e)
{
    var br = sender as Gecko.GeckoWebBrowser;
    if (br.Url == e.Uri)
    {
        form.Controls.Remove(po.wb);
        ThreadsCompleted();
        manualReset.Set();
    }
}
public void Scrape(对象o)
{
po=(PoolObjects)o;
//和阿宝一起做事
调用((MethodInvoker)委托
{
采购订单.表单.控件.添加(采购订单.工作分解);
po.wb.DocumentCompleted+=新事件处理程序(wb_DocumentCompleted);
采购订单wb.Navigate(采购订单链接);
});
}
void wb_DocumentCompleted(对象发送方,Gecko.Events.GeckoDocumentCompletedEventArgs e)
{
var br=发送方为Gecko.GeckoWebBrowser;
if(br.Url==e.Uri)
{
表单.控件.删除(po.wb);
线程已完成();
手动复位。设置();
}
}

要么你有打字错误,要么你有一个巨大的bug。你有

else if (scraper[j].tred.IsAlive)
{
    scraper[j] = null;
}
我想你想要
如果(!scraper[j].tred.IsAlive)
。否则,最终将覆盖数组中的活动
刮片
引用

更重要的是,试图维护
Scraper
对象的数组会给您带来很多您实际上不需要的复杂性。您已经有了控制可以拥有多少并发线程的信号量,因此
Scraper
对象的数组是不必要的

此外,您不希望等待一大堆
ManualResetEvent
对象
WaitAll
不能等待超过63个项目,因此如果您的项目列表中有超过63个项目,
WaitAll
不会为您执行此操作。我在下面展示了一种更好的方法来确保所有的工作都完成了

for (int i = 0; i < arrScrapeboxItems.Count; i++)
{
    pool.WaitOne();
    ScrapeBoxItems sbi = (ScrapeBoxItems)arrScrapeboxItems[i];

    wb = new Gecko.GeckoWebBrowser();
    PoolObjects po = new PoolObjects();
    po.link = sbi.link;
    // more initialization of po ...

    // and then start the thread
    Thread t = new Thread(ScrapeThreadProc);
    t.Start(po);
}
// Here's how you wait for all of the threads to complete.
// You have your main thread (which is running here) call `WaitOne` on the semaphore 5 times:
for (int i = 0; i < 5; ++i)
{
    pool.WaitOne();
}

private void ScrapeThreadProc(object o)
{
    var po = (PoolObjects)o;
    Scraper scraper = new Scraper();
    // initialize your Scraper object
    scraper.ThreadsCompleted += new Scraper.ThreadsHandler(frmMain_NextThreadItemsCompleted);

    scraper.Scrape(po);

    // scraping is done. Dispose of the scraper and the po.

    // and then release the semaphore
    pool.Release();
}
for(int i=0;i
这将大大简化您的代码

让主线程等待信号量5次的想法非常简单。如果主线程可以在不调用
Release
的情况下获取信号量5次,那么您就知道没有任何其他作业在运行

还有其他方法可以做到这一点,但它们需要对代码进行更复杂的重构。您应该查看任务并行库,具体来说,它将为您处理线程。您可以将并发线程的最大数量设置为5,这样就不会同时运行太多线程

您还可以使用带有
BlockingCollection
的生产者/消费者设置或其他一些共享队列来实现这一点


在这两种情况下,最终都会创建5个持久性线程,它们协同处理列表中的项目。这通常比为每个项目创建一个线程更有效。

看起来有两个可能的问题。您对每个线程使用相同的Web浏览器,而不是创建一个新的并将其添加到表单中。第二,您没有在表单上指定web浏览器的坐标和大小。它们可能相互重叠。@TyCobb我已将浏览器对象移到内部进行循环,但没有用,同样的问题。我有鳕鱼