2010-02-06 32 views
12

Tôi đang phát triển ứng dụng C# Winforms, một phần của ứng dụng sẽ tải tệp lên máy chủ web bằng cách sử dụng AsyncUpload (sử dụng nó, do cần sử dụng gọi lại porgress), Trong C# chương trìnhC#: Chặn cuộc gọi chức năng cho đến khi điều kiện đáp ứng

tôi đã nhận một đơn giản cho vòng lặp mà các cuộc gọi chức năng tải lên

for(int i=0;i < 10 ; i++) 
{ 
    Uploadfun(); 
} 

Và những niềm vui hiện một số ma thuật:

Uploadfun() 
    { 
    // Logic comes here 

    // webClient.UploadFileAsync runs a 2nd thread to perform upload .. 
    webClient.UploadFileAsync(uri, "PUT", fileNameOnHD); 

} 

Và một callback mà được gọi là w hen tải lên Async được thực hiện

Upload_Completed_callback() 
{ 
    //Callback event 
} 

Sửa

Logic trình tự:

  1. Fun được gọi (từ vòng lặp)
  2. Logic Fun được thực hiện và thực hiện ..
  3. Quay lại vòng lặp
  4. Gọi lại sẽ được gọi là eventuall y, khi UploadFileAsync (đang chạy một số logic trong một chuỗi khác) sẽ kết thúc

Vấn đề nằm ở điểm thứ ba, khi thực hiện di chuyển trở lại vòng lặp, tôi cần chặn vòng lặp tiếp tục cho đến khi gọi lại được gọi.

+3

Bạn có quyền truy cập vào hoạt động 'fun' không? Bạn có lẽ nên xem xét việc cung cấp một giao diện đồng bộ mà trên đó API async được triển khai. –

+0

Cách bạn mô tả nó, mã của bạn có vẻ tuần tự và đơn luồng, có nghĩa là cho đến khi hàm 'callback' được gọi là vòng lặp sẽ không tiếp tục. Vui lòng sửa tôi nếu tôi sai bằng cách đưa ra giải thích chi tiết hơn. –

+0

@Madi: Sau đó, bạn đang làm điều này ngược. Bạn nên sử dụng phiên bản đồng bộ của 'UploadFile' ở cốt lõi của logic và sử dụng một async API trên đầu trang của nó nếu bạn cần nó. –

Trả lời

20

Vì vậy, nếu tôi hiểu chính xác, bạn muốn gọi UploadFileAsync sau đó chặn cho đến khi cuộc gọi không đồng bộ đã nhấn gọi lại của bạn. Nếu như vậy, tôi muốn sử dụng AutoResetEvent tức

private readonly AutoResetEvent _signal = new AutoResetEvent(false); 

fun() 
    { 
    // Logic comes here 

    // runs a 2nd thread to perform upload .. calling "callback()" when done 
    webClient.UploadFileAsync(uri, "PUT", fileNameOnHD); 

    _signal.WaitOne(); // wait for the async call to complete and hit the callback  
} 



callback() 
{ 
    //Callback event 
    _signal.Set(); // signal that the async upload completed 
} 

Sử dụng AutoResetEvent có nghĩa là nhà nước được tự động thiết lập lại sau khi Set đã được gọi và một tiểu trình đang chờ nhận được tín hiệu thông qua WaitOne

+0

khi sử dụng Waitone() sau khi uploadAsync, Chương trình đang tạm dừng và Cuộc gọi lại không được gọi. –

+0

okie .. tôi đã khắc phục sự cố tạm dừng, được gọi là fun() trong một chuỗi riêng biệt, "rõ ràng" gọi nó trong chuỗi chính đang gây ra vấn đề !, @Juliet Kinda đã giúp chỉ ra vấn đề .. cảm ơn cả hai bạn =) –

4

Trong phương pháp C# chặn theo mặc định, vì vậy bạn không cần phải làm gì cả. Tôi giả định rằng đối với một số lý do bạn đang gọi một phương pháp không chặn bắt đầu một nhiệm vụ nền/thread/bất cứ điều gì và cung cấp cho bạn một cuộc gọi lại khi nó được thực hiện. Bạn muốn gọi phương thức asynchonous này theo cách đồng bộ.

Bạn có thể gọi fun từ bên trong cuộc gọi lại. Nội dung nào đó dọc theo các dòng này (mã giả):

int n; 

callFunTenTimes() 
{ 
    n = 0; 
    fun(n); 
} 

callback() 
{ 
    ++n; 
    if (n < 10) 
     fun(n); 
    else 
     print("done"); 
} 

Điều này tương tự như continuation passing style.

Lợi thế của phương pháp này là bạn cũng có thể làm cho phương thức của bạn không đồng bộ mà không cần thêm bất kỳ chuỗi, khóa hoặc logic bổ sung nào - bạn chỉ cần cung cấp chức năng gọi lại mà khách hàng của bạn có thể đăng ký. Nó hoạt động tốt trong một môi trường hướng sự kiện.

+0

Thats vui nhộn. Tôi đã suy nghĩ về vấn đề của riêng tôi dọc theo những dòng này: có chức năng gọi lại làm 'thịt' của những gì vòng lặp được sử dụng để làm. Giải pháp này dường như giữ thời gian chờ ở mức tối thiểu. – Joe

+0

tôi cần phiên bản async vì nó cung cấp gọi lại "tiến trình" là yêu cầu cốt lõi. –

+0

@Madi D: Nếu yêu cầu là việc tải lên phải hoạt động không đồng bộ, tại sao không làm cho hàm của bạn có chức năng async quá, với một cuộc gọi lại? Bạn có thể giải thích thêm về những gì bạn đang sử dụng này cho? Đây có phải là một ứng dụng WinForms, ASP.NET, v.v. –

1

Vấn đề là ở đây:

for(int i=0;i < 10 ; i++) 
{ 
    fun(); <-- if we block until this function finishes here, we stop the UI thread 
} 

Việc bạn đang làm là tuần tự.Và nếu bạn không thể đủ khả năng để chặn thread UI, di chuyển vòng ra khỏi thread UI:

volatile downloadComplete; 

void DownloadUpdates() 
{ 
    ThreadPool.QueueUserWorkItem(state => 
     for(int i = 0; i < 10; i++) 
     { 
      downloadComplete = false; 
      webClient.UploadFileAsync(uri, "PUT", fileNameOnHD); 
      while(!downloadComplete) { Thread.Sleep(1); } 
     }); 
} 

Upload_Completed_callback() 
{ 
    downloadComplete = true; 
} 

Bây giờ bạn có thể chặn việc thực hiện các vòng lặp mà không ngăn chặn thread UI của bạn, và bạn cũng nhận được lợi ích của chỉ báo tiến trình từ lớp webclient.

+0

Không sử dụng biến boolean cho điều này, trình biên dịch có thể tối ưu hóa nó đi (điều này sẽ gây ra hành vi không bao giờ tiếp tục đề cập đến OP). zebrabox cho thấy đúng cách để làm điều đó, với một đối tượng sự kiện chờ đợi. –

+1

@Ben: Tôi đánh giá cao ý kiến ​​của bạn, nhưng tôi nghĩ rằng họ đang gây hiểu nhầm. Đầu tiên, trình biên dịch sẽ không tối ưu hóa bool đi miễn là nó được sử dụng hoặc được gán ở đâu đó (và có lẽ nó là). Thứ hai, chờ đợi trên một bool và resetEvents là các cách hợp lệ để chặn một luồng, cả hai đều là "đúng cách để làm điều đó", không phải là "sai", chọn một hay khác phụ thuộc vào thị hiếu của lập trình viên. – Juliet

+0

Cảm ơn rất nhiều cho câu trả lời thực sự hữu ích, kết thúc lên kết hợp luồng từ giải pháp của bạn với giải pháp resetEvent @ zebrabox, và bây giờ nó đang hoạt động .. =) –

3

Zebrabox có quyền sử dụng WaitHandle. Trong khi giải pháp của Juliet không hoạt động, chuỗi thực hiện chờ đợi sẽ tiêu thụ một lượng đáng kể bộ vi xử lý tương ứng với WaitHandle, mà về cơ bản sẽ không hoạt động.

+0

+1 chiếu sáng trên cả hai câu trả lời hàng đầu (với tôi) .. –

+0

Nó sẽ không tiêu tốn rất nhiều bộ xử lý, nhưng nó có thể ngăn hệ thống đưa CPU vào trạng thái không hoạt động sâu hơn và do đó rút pin nhanh hơn máy tính xách tay. –

Các vấn đề liên quan