سؤال

أقوم بتطوير تطبيق C # WinForms، سيتم تحميل جزء من التطبيقات على الملفات إلى خادم الويب باستخدام ASYNCUPLOAD (باستخدامه، بسبب الحاجة إلى استخدام اتصال Porgress)، في برنامج C #

حصلت على حلقة بسيطة تسمدع وظيفة التحميل

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

والمرح يفعل بعض السحر:

Uploadfun()
  { 
  // Logic comes here

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

 }

وبدون اتصال يسمى عند إجراء تحميل ASYNC

Upload_Completed_callback()
{
  //Callback event
}

يحرر

تسلسل المنطق:

  1. يتم استدعاء المرح (من حلقة)
  2. يتم تنفيذ المنطق المرح وفعلت ..
  3. يعود إلى حلقة
  4. سيتم استدعاء رد الاتصال في نهاية المطاف، عندما تنتهي UploadFileAsync (التي تعمل بعض المنطق في مؤشر ترابط آخر)

المشكلة في النقطة الثالثة، عندما يتحرك التنفيذ مرة أخرى إلى حلقة، أحتاج إلى حظر الحلقة من المتابعة حتى يتم استدعاء الاتصال.

هل كانت مفيدة؟

المحلول

لذلك إذا فهمت بشكل صحيح، تريد الاتصال UploadFileAsync ثم حظر حتى تضغط استدعاء ASYNC رد الاتصال الخاص بك. إذا كان الأمر كذلك، فسأستخدم AutoResetEvent بمعنى آخر

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
 }

استخدام AutoResetEvent يعني أن الحالة يحصل إعادة تعيين تلقائيا بعد Set وقد تم استدعاء وخيط الانتظار يتلقى الإشارة عبر WaitOne

نصائح أخرى

في حظر طرق C # بشكل افتراضي، لذلك يجب ألا تحتاج إلى فعل أي شيء. أفترض أنه بالنسبة لسبب ما كنت تتصل بطريقة غير حظر تبدأ مهمة / موضوع خلفية / أي مكان ويمنحك رد اتصال عند القيام به. تريد استدعاء هذه الطريقة الجميلة بطريقة متزامنة.

تستطيع الاتصال fun من داخل رد الاتصال. شيء على طول هذه الخطوط (رمز الزائفة):

int n;

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

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

هذا يشبه استمرار النمط.

ميزة لهذه الطريقة هي أنه يمكنك أيضا جعل طريقتك غير متزامن دون إضافة أي خيوط إضافية أو أقفال أو منطق إضافي - يمكنك فقط توفير وظيفة رد الاتصال التي يمكن لعملائك الاشتراك فيها. يعمل بشكل جيد في بيئة يحركها الأحداث.

Zebrabox لديه حق باستخدام waithandle. في حين أن حل Juliet يعمل، فإن الخيط الذي يؤدي الانتظار في الدوران سيستهلك كمية كبيرة من المعالج بما يتناسب مع waithandle، والذي من شأنه أن يجلس بشكل أساسي الخمول.

المشكلة هنا:

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

ما تفعله هو متتابع. وإذا كنت لا تستطيع حظر مؤشر ترابط UI، حرك الحلقة من مؤشر ترابط 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;
}

يمكنك الآن حظر تنفيذ الحلقة دون إيقاف مؤشر ترابط UI الخاص بك، كما تحصل أيضا على فائدة مؤشرات التقدم من فئة WebClient.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top