downloaddataasync + delegate c#은 메인에서 작동하지만 클래스 기능에서는 작동하지 않습니다.

StackOverflow https://stackoverflow.com/questions/1653108

  •  22-07-2019
  •  | 
  •  

문제

나는이 사람들 코드를 달렸다. 그것은 메인으로 일했지만 수업에 넣을 때 작동하지 않습니다. 왜요?이 맥락에서 WebClient.DownloadDataAsync () 메소드를 사용하는 방법은 무엇입니까?

BC Data == NULL이 충돌하고 NULL 예외를 던졌습니다.

public class Test2
    {
        public void func()
        {
            byte[] data = null;
            WebClient client = new WebClient();
            client.DownloadDataCompleted +=
                delegate(object sender, DownloadDataCompletedEventArgs e)
                {
                    data = e.Result;
                };
            Console.WriteLine("starting...");
            client.DownloadDataAsync(new Uri("https://stackoverflow.com/questions/"));
            while (client.IsBusy)
            {
                Console.WriteLine("\twaiting...");
                Thread.Sleep(100);
            }
            Console.WriteLine("done. {0} bytes received;", data.Length);
        }
    }

//i tried calling on form_load and a button click
new Test2().func();
도움이 되었습니까?

해결책

이 코드에는 a가 있습니다 경쟁 조건 데이터 필드에서. 다운로드 dataCoMpleted 익명 대의원은 데이터와 다른 스레드에서 호출됩니다. 길이의 호출이 이루어지고 다운로드 datACEMBleted가 ISBUSY라고 불리는 시점에서 ISBUSY가 거짓이됩니다. 누가 데이터에 먼저 액세스하는 사람의 두 스레드 사이의 경쟁입니다. 기본 스레드가 데이터를 호출하면 데이터가 다운로드 스레드에서 설정되기 전에 NULL 참조 예외가 나타납니다. DASTERCOMPLETED DELETE가 데이터를 설정하기 전에 Thread.Sleep () 호출을 추가하여 항상 경주를 느슨하게하도록 강제로 쉽게 알 수 있어야합니다.

스레드의 상태는 다음과 같습니다.

Main Thread             Download Thread     client.IsBusy
Waiting....             downloading...      true
leaves waiting loop     calls delegate      false
calls data.Length       data = e.Result

마지막 줄을 먼저 실행할 스레드를 알 수있는 방법이 없습니다. 다중 프로세서 머신에서 두 가지 모두 동시에 실행될 수 있습니다.

이것은 모두 타이밍을 기반으로하기 때문에 때때로 작동하며 때로는 실패합니다. Mutliple 스레드에서 액세스하는 모든 데이터에 대해 일종의 동기화 (잠금)가 필요합니다.

다른 팁

Winform (AS shf301 지적했다), 나는 나를 위해 작동하는 코드를 수정했다.

private void button1_Click(object sender, EventArgs e)
{
    func();
}
void func()
{
    WebClient client = new WebClient();
    byte[] data = null;
    long rcv = 0; //last number of bytes received

    //check data received for progress
    client.DownloadProgressChanged += delegate(object sender, DownloadProgressChangedEventArgs e)
    {
        if (e.BytesReceived - rcv > 1000)
        {
            Console.WriteLine("\tBytes Received: " + e.BytesReceived.ToString());
            rcv = e.BytesReceived;
        }
        //else don't report
        Thread.Sleep(1);
    };
    client.DownloadDataCompleted +=
        delegate(object sender, DownloadDataCompletedEventArgs e)
        {
            data = e.Result;
            Console.WriteLine("done. {0} bytes received;", data.Length);
        };
    Console.WriteLine("starting...");

    //fire and forget
    client.DownloadDataAsync(new Uri("http://stackoverflow.com/questions/"));
}

출력이 있습니다.

starting...
    Bytes Received: 8192
    Bytes Received: 11944
    Bytes Received: 15696
    Bytes Received: 20136
    Bytes Received: 24232
    Bytes Received: 28040
    Bytes Received: 32424
    Bytes Received: 36176
    Bytes Received: 40616
    Bytes Received: 44712
    Bytes Received: 48269
done. 48269 bytes received;

그것은 나를 위해 작동합니까?

C:\TEMP\ConsoleApplication5\bin\Debug>ConsoleApplication5.exe
starting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
    waiting...
done. 48178 bytes received;

결과가 루프를 기다리는 경우 비동기 방법을 사용하는 점은 무엇입니까? 동기 버전 만 사용하십시오.

public class Test2
    {
        public void func()
        {
            WebClient client = new WebClient();
            byte[] data = client.DownloadData(new Uri("http://stackoverflow.com/questions/"));
            Console.WriteLine("done. {0} bytes received;", data.Length);
        }
    }

//i tried calling on form_load and a button click
new Test2().func();
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top