代码之家  ›  专栏  ›  技术社区  ›  blez

C问题中的多线程下载程序

  •  0
  • blez  · 技术社区  · 15 年前

    目前我有使用httpwebrequest/response的多线程下载程序类。一切正常,速度很快,但是…问题是,数据在下载到另一个应用程序时需要流式传输。这意味着它必须按正确的顺序进行流传输,首先是第一个块,然后是队列中的下一个块。目前我的下载程序类是sync,download()返回byte[]。例如,在我的异步多线程类中,列出4个空元素(用于插槽),然后使用download()函数将插槽的每个索引传递给每个线程。这模拟了同步,但这不是我需要的。我应该如何做队列的事情,以确保数据流一旦第一块开始下载。

    3 回复  |  直到 15 年前
        1
  •  2
  •   dthorpe    15 年前

    如果您的问题是如何确定哪个线程正在下载第一个块,以及第一个块何时可以使用,请为每个线程使用一个事件,并跟踪已分配给哪个线程的块。跟踪传递给第一个线程的事件(将下载第一个数据块)、传递给第二个线程的事件(用于第二个数据块)等。主线程或另一个后台线程(避免阻塞ui线程)等待第一个事件。当第一个线程下载完它的块时,它设置/发送第一个事件。等待的线程随后将唤醒,并可以使用第一个数据块。

    其他下载线程也可以这样做,在完成时发送各自的事件。使用手动重置事件,这样即使没有人在等待,事件也会保持信号。当需要数据块顺序的线程处理完第一个数据块时,它可以等待第二个事件。如果第二个事件已经发出信号,那么等待将立即返回,线程可以开始处理第二个数据块。

    对于非常大的下载,您可以循环使用事件和线程。它们完成的顺序并不重要,只要使用数据块的线程按顺序使用它们并按顺序等待相应的事件。

    如果你聪明小心,你可能只需要使用一个事件就可以做到这一切:创建一个最初设置为空的数据块指针/对象的全局数组,工作线程下载数据块并将完成的块分配给全局数组中各自的槽,然后发信号给共享事件。使用者线程保留一个数据块计数器,以便它知道下一个需要处理的数据块,等待共享事件,并在发出信号时查看全局数组中的下一个插槽,以查看是否有数据出现在那里。如果序列中的下一个插槽中仍然没有数据,则使用者线程返回到等待事件。您还需要一种方法让工作线程知道下一步应该下载哪个数据块—一个受互斥锁保护或使用interlockedd/exchange访问的全局计数器就足够了。每个工作线程递增全局计数器并下载该数据块编号,并将结果分配给数据块全局列表中的第n个槽。

        2
  •  0
  •   feroze    15 年前

    你能告诉我下载的代码,以及启动多个异步线程的代码吗?

    也许我没有完全理解你的场景,但是如果我是你,我会使用async(从responsestream开始)。然后我会做以下的…

    void StartReading(Stream responseStream)
    {
        byte [] buffer = new byte[1024];
        Context ctx = new Context();
        ctx.Buffer = buffer;
        ctx.InputStream = responseStream;
        ctx.OutputStream = new MemoryStream(); // change this to be your output stream
    
        responseStream.BeginRead(buffer, 0, buffer.Length; new AsyncCallback(ReadCallback), ctx);
    }
    
    void ReadCallback(IAsyncResult ar)
    {
        Context ctx = (Context)ar.AsyncState;
        int read = 0;
        try {
            read = ctx.InputStream.EndRead(ar);
            if (read > 0)
            {
                ctx.OutputStream.Write(ctx.Buffer, 0, read);
                // kick off another async read
                ctx.InputStream.BeginRead(ctx.Buffer, 0, ctx.Buffer.Length, new AsyncCallback(ReadCallback), ctx);
            } else {
                ctx.InputStream.Close();
                ctx.OutputStream.Close();
            }
         } catch {
         }
    }
    
    }
    
        3
  •  0
  •   George Stocker NotMe    15 年前

    要创建一个同步的多线程下载程序,您需要创建正确的数据结构,而不仅仅是 byte[] 数据。

    步骤:

    1. 根据每个线程下载的内容大小或固定大小的内容下载程序(大约500KB)将下载内容分成多个块。
    2. 启动线程时,指定块索引-第一部分、第二部分等
    3. 下载可用时,根据块索引对齐最终内容。

    如果您感兴趣,可以查看 prozilla (c,基于linux的-at)或axel。