views:

143

answers:

2

There is a string array myDownloadList containing 100 string URIs. I want to start 5 thread jobs that will pop next URI from myDownloadList (like a stack) and do something with it (download it), until there is no URIs left on a stack (myDownloadList).

What would be the best practice to do this?

+6  A: 

Use the ThreadPool, and just setup all of your requests. The ThreadPool will automatically schedule them appropriately.

This will get easier with .NET 4, using the Task Parallel Library. Setting up each request as a Task is very efficient and easy.

Reed Copsey
I'm stuck with ThreadPool on "The number of WaitHandles must be less than or equal to 64." error.
Davorin
If you're using STA (which you probably are), you can only use WaitAll(handles) on 64 wait handles. Just wait on each handle individually in a loop, instead, and it'll work fine, ie: foreach(var handle in handles) handle.WaitOne(); This limitation is documented at: http://msdn.microsoft.com/en-us/library/z6w25xa6.aspx
Reed Copsey
+1  A: 

Make sure each thread locks the myDownloadList when accessing it. You could use recursion to keep getting the latest one, then when the list is 0 it can just stop the function.

See the example below.

public static List<string> MyList { get; set; }
public static object LockObject { get; set; }

static void Main(string[] args)
{
    Console.Clear();

    Program.LockObject = new object();

    // Create the list
    Program.MyList = new List<string>();

    // Add 100 items to it
    for (int i = 0; i < 100; i++)
    {
        Program.MyList.Add(string.Format("Item Number = {0}", i));
    }

    // Start Threads
    for (int i = 0; i < 5; i++)
    {
        Thread thread = new Thread(new ThreadStart(Program.PopItemFromStackAndPrint));

        thread.Name = string.Format("Thread # {0}", i);

        thread.Start();
    }
} 


public static void PopItemFromStackAndPrint()
{
    if (Program.MyList.Count == 0)
    {
        return;
    }

    string item = string.Empty;

    lock (Program.LockObject)
    {
        // Get first Item
        item = Program.MyList[0];

        Program.MyList.RemoveAt(0);
    }

    Console.WriteLine("{0}:{1}", System.Threading.Thread.CurrentThread.Name, item);

    // Sleep to show other processing for examples only
    System.Threading.Thread.Sleep(10);

    Program.PopItemFromStackAndPrint();
}
David Basarab
I would recommend the use of a while loop rather than calling yourself recursively. This can ... yes I have to say it ... create a stack-overflow.
csharptest.net