Question

I'm trying to fix this issue from 2-3 hours but unable to fix it. I'm trying to download a file in three parts three threads. the problem is when one part is completed, other threads stop downloading.

Example: let's say i want to download 300kb 
part1->t1->100kb
part2->t2->100kb  //if this thread get completed then other two become unresponsive.
part3->t3->100kb     

Code i'm working with (Modified and shorter one but addresses my issue )

//inside a function
            WebResponse wresp = wreq.GetResponse();
            long e1 = wresp.ContentLength / 3;
            long e2 = 2*e1;
            long e3 = wresp.ContentLength;
            wreq.Abort();
            wresp.Close();
            wreq = null;
            wresp = null;
            byte[] buff1 = new byte[1500];
            byte[] buff2 = new byte[1500];
            byte[] buff3 = new byte[1500];
            HttpWebRequest hr1 = (HttpWebRequest)WebRequest.Create(textBox1.Text);
            hr1.AddRange(0, e1-1);
            WebResponse wresp1 = hr1.GetResponse();
            HttpWebRequest hr2 = (HttpWebRequest)WebRequest.Create(textBox1.Text);
            hr2.AddRange(e1,e2-1);
            WebResponse wresp2 = hr2.GetResponse();
            HttpWebRequest hr3 = hr1;//(HttpWebRequest)WebRequest.Create(textBox1.Text);
            hr3.AddRange(e2,e3);
            WebResponse wresp3 = hr3.GetResponse();
            Stream response1 = wresp1.GetResponseStream();
            Stream  response2 = wresp2.GetResponseStream();
            Stream response3 = wresp3.GetResponseStream();
            Stream f1, f2, f3;
            f1 = File.Create("Part1");
            f2 = File.Create("Part2");
           f3 = File.Create("Part3");
            int bytesRead=0, bytesProcessed=0;
            long total1=e1, total2=e2-e1, total3=e3-e2;
            int x1=0, x2=0, x3=0;
            Thread t1 = new Thread(() =>download(hr1, wresp1, buff1,response1,f1,bytesRead, bytesProcessed,total1,x1));
            t1.Name = "1";
            Thread t2 = new Thread(() => download(hr2, wresp2, buff2, response2, f2, bytesRead, bytesProcessed,total2,x2));
            t2.Name = "2";
            Thread t3 = new Thread(() => download(hr3, wresp3, buff3, response3, f3, bytesRead, bytesProcessed, total3,x3));
            t3.Name = "3";
            t1.Start();
            t2.Start();
            t3.Start();
            }

        }
        }

    private download(HttpWebRequest hr2, WebResponse wresp2, byte[] buff, Stream response, Stream f,int bytesRead,long bytesProcessed,long total,int x)
    {
        do
        {
            lock (lockerObj)
            {
                bytesRead = response.Read(buff, 0, buff.Length);
                bytesProcessed += bytesRead;
                f.Write(buff, 0, bytesRead);
                x = Convert.ToInt32(Thread.CurrentThread.Name) - 1;
                pb[x].Invoke((Action)delegate
                {
                    pb[x].Value = Convert.ToInt32(bytesProcessed * 100 / total);

                });
                if (bytesProcessed >= total)
                {
                    Thread.CurrentThread.Abort();
                    break;
                }
                lb[x].Invoke((Action)delegate
                {
                    lb[x].Text = "Downloaded " + Convert.ToDouble((bytesProcessed * 100 / total)).ToString() + "%";
                    label4.Text = "thread" + (x + 1);
                });

            }
        } while (bytesProcessed<=total && bytesRead>=0 );
    }
    static readonly Object lockerObj=new Object(); //at global level

The application ui remains responsive and from debugging i realized that each thread is exiting at same time. So the question is why the other threads are not completing their parts.

enter image description here

Was it helpful?

Solution

You have this condition at the end of the loop in your download method:

while (bytesProcessed<=0 && bytesRead>0 );

That's your problem. The first time through the loop, bytesProcessed is incremented by the number of bytes read, which makes it greater than 0, which causes the condition to be false and the loop exits.

You'll never do more than one iteration in the loop.

By the way, not every response will have a valid ContentLength. Web pages regularly provide no Content-Length header, in which case the ContentLength property will be -1. Even if the page does provide a Content-Length header, there's no guarantee that it's correct. So in the general case you can't guarantee that you've received the entire contents.

As Servy pointed out in his comment, splitting the download among multiple threads is unlikely to improve performance and fact could very likely cause the download to go slower. That's especially true if a site sees you making three concurrent requests and decides to rate limit or block you. In general you're better off doing a normal download with a single HttpWebRequest. It's more reliable, it simplifies your code, and probably will perform better than the overly complex multithreaded version you've coded.

OTHER TIPS

I agree with @Kyle Pittman. It's most probably BytesRead and BytesProcessed variables are the cause of your problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top