1

i'm doing a little download manager with C# and WPF.

In my logic there is a main thread (for UI), a thread for manage connection and a thread for each download, until a maximum download number i defined with a semaphore.

Every time the user want to download something it adds a custom object DownloadDetails in a shared queue, the connection thread dequeue it and make another thread do the actual download.

For a single file it works fine, but for multiple files looks like more threads try to download the same file, trying to write the same file on local drive and crashing when writing stream.

Here some snippets of my implementation

in main form:

private Thread connectionManager; 

when clickin download i add the new download (they are all correct, i checked it) and start the connection thread only if its not already started:

downloadList.Enqueue(newDownload); if (connectionManager == null || !connectionManager.IsAlive) { connectionManager = new Thread((ThreadStart)delegate { ManageDownload(); }); connectionManager.SetApartmentState(ApartmentState.STA); connectionManager.IsBackground = true; connectionManager.Start(); } 

the download manager thread do this:

private void ThreadStartingPoint() { downloadDetails singleDownload = new downloadDetails(); while (downloadList.TryDequeue(out singleDownload)) { downloadSemaphore.WaitOne(); Thread singleDownloadThread = new Thread((ThreadStart)delegate { myDownloadClass.Download(singleDownload); }); singleDownloadThread.SetApartmentState(ApartmentState.STA); singleDownloadThread.IsBackground = false; singleDownloadThread.Start(); } } 

after completing the download (or canceling, or getting an error), the single thread do a downloadSemaphore.Release();

the problems is that the myDownloadClass.Download looks to get multiple time the same parameter when starting 2 or more downloads quickly

i have to use delegate because single download threads needs to update UI on main thread

how can i solve this? Thank you :)

1 Answer 1

3

This fragment

while (downloadList.TryDequeue(out singleDownload)) { downloadSemaphore.WaitOne(); Thread singleDownloadThread = new Thread((ThreadStart)delegate { myDownloadClass.Download(singleDownload); }); ... } 

is capturing the loop-variable.

The fix:

while (downloadList.TryDequeue(out singleDownload)) { string localCopy = singleDownload; downloadSemaphore.WaitOne(); Thread singleDownloadThread = new Thread((ThreadStart)delegate { myDownloadClass.Download(localCopy); }); ... } 

As a more general advice, i would use Tasks and maybe the Parallel class to build a downloadmanager.

Sign up to request clarification or add additional context in comments.

4 Comments

are you sure? debugging it i always have a different value because the "TryDequeue" actually remove the value from the queue.. and this loop is done by a single thread so it can't be done multiple times in the same moment
Try it with the localCopy fix. It fits the looks like more threads try to download the same file symptom.
tried.. and.. working! thank you :) but i still don't understand why it works, how can this happen?
The anonymous method that you feed to singleDownloadThread is doing the capturing. I've added a link.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.