Ожидание с потоками - PullRequest
       27

Ожидание с потоками

3 голосов
/ 08 марта 2012

В основном мне нужно заняться, пока на веб-странице не появится какой-нибудь html. Я создал следующий код, чтобы ждать меня:

public void ExecuteBusyWaitThreads()
    {

        foreach (Canidate canidate in allCanidates)
        {
            Thread newThread = new Thread(delegate()
            {
                BusyWait(canidate);
            });

            newThread.Start();
        }
    }

    public bool BusyWait(Canidate canidate)
    {
        //hit that url, and wait for the claim all button to appear
        string page = null;
        while (found == false)
        {
            HttpWebRequest request = Canidate.GetHTTPRequest(canidate.URL);
            //make sure we add the authentication cookes to the request
            request = Canidate.AddCookiesToRequest(request, canidate.GetCookies());
            page = new Canidate().GetPage(request);
            if (page.ToLower().Contains("claim all"))
            {
                found = true;
                NotifyAllThreads();
            }
        }
        return true;
    }

Итак, если бы у меня было 8 canidates, это породило бы 8 потоков, каждый из которых ищет claim all для отображения на веб-странице. found является глобальной переменной. Как только один из потоков находит claim all, все они должны получить залог.

У меня есть пара вопросов об этом подходе. Во-первых, это хороший подход. Во-вторых, каждый поток получит свою собственную «копию» занятой функции ожидания. Под этим я подразумеваю, может ли один поток выгружать другой и изменять данные в этой функции, или каждый из них получает копию переменных, объявленных внутри функции. Обратите внимание, что обе эти функции находятся внутри одного и того же объекта.

Ответы [ 4 ]

5 голосов
/ 08 марта 2012

Прежде чем ответить на ваши вопросы, я должен указать, что вы совершили вопиющий акт закрытия над переменной цикла .

Во-первых, это хороший подход.

Нет, не совсем. Произвольное создание потоков обычно не очень хорошая идея. Лучше использовать методы пула потоков. Это можно сделать с помощью ThreadPool.QueueUserWorkItem или Task класса.

Во-вторых, каждый поток получит свою собственную "копию" функции ожидания занятости. Под этим я подразумеваю, может ли один поток выгружать другой и изменять данные в эта функция, или каждый из них получает копию объявленных переменных внутри функции.

Каждый работающий экземпляр BusyWait получит свою собственную копию всех локальных переменных (т. Е. page и request). Поскольку found объявлено (предположительно в любом случае) в нелокальной области, то оно будет совместно использоваться всеми запущенными экземплярами BusyWait. Как следствие, ваши текущие операции чтения и записи в found не являются поточно-ориентированными, поскольку на них нет механизмов синхронизации.

2 голосов
/ 08 марта 2012

Все потоки получают свои собственные копии локальных переменных (в данном случае только string page).

Общая переменная found должна быть объявлена ​​как volatile

Это редкая ситуация, когда вызов Thread.Sleep() может принести пользуВставьте немного передышки между звонками на один и тот же сайт.

2 голосов
/ 08 марта 2012

Каждый поток работает со своей собственной копией переменных.

Однако я бы изменил свой appoarch зря. Использование найденной переменной не является потокобезопасным. Возможно, что одновременно будет найдено более одного потока. Также очень возможно, что один поток будет читать его, в то время как другой пишет. [lock][1] мог бы избежать этого.

Лучший способ решить эту проблему - использовать EventWaitHandle . Таким образом, вам на самом деле не нужно беспокоиться о блокировке, и вы можете встроить режим ожидания или тайм-аут, так что, если не будет отображено «все заявки», ваши потоки не будут работать дольше, чем вы хотите.

internal class ExampleOnExecute
{
    private static EventWaitHandle _stopEvent;

    public static EventWaitHandle StopEvent
    {
        get { return _stopEvent ?? (_stopEvent = new EventWaitHandle(false, EventResetMode.ManualReset)); }
    }

    public static void SpinOffThreads(IEnumerable<object> someCollection)
    {
        foreach(var item in someCollection)
        {
            // You probably do not want to manualy create a thread since these ideally would be small workers
            // and action BeingInvoke runs in the ThreadPool
            Action<object> process = BusyWait;

            process.BeginInvoke(item, null, null);
        }
    }

    private static void BusyWait(object obj)
    {
        // You can wait for however long you like or 0 is not waiting at all
        const int sleepAmount = 1;

        //     Blocks the current thread until the current instance receives a signal, using
        //     a System.TimeSpan to specify the time interval.
        //
        // Parameters:
        //   timeout:
        //     A System.TimeSpan that represents the number of milliseconds to wait, or
        //     a System.TimeSpan that represents -1 milliseconds to wait indefinitely.
        //
        // Returns:
        //     true if the current instance receives a signal; otherwise, false.
        while (!StopEvent.WaitOne(TimeSpan.FromMilliseconds(sleepAmount)))
        {
            // Do you work here
            var foundIt = DidIFindIt();

            if (foundIt)
            {
                // Signal all threads now to stop working we found it.
                StopEvent.Set();
            }
        }
    }

    private static bool DidIFindIt()
    {
        return true;
    }
}

Здесь является превосходной БЕСПЛАТНОЙ книгой по Threading .

2 голосов
/ 08 марта 2012

Во-вторых, каждый поток получит свою собственную "копию" функции ожидания занятости

Каждый поток выполнит функцию со своим собственным пространством стека, что означает, что любая переменнаялокально внутри вашей функции будет принадлежать потоку, в котором она выполняется.Если у вас есть глобальная переменная, например, переменная found, изменяемая внутри функции, вам нужно настроить механизм синхронизации так, чтобы доступ к ней не происходил из нескольких потоков одновременно, так как это приведет к трудным поискам ошибок.и много ужасов, о которых вы даже не мечтаете!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...