C #: حظر مكالمة دالة حتى التقى الشرط
سؤال
أقوم بتطوير تطبيق 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
}
يحرر
تسلسل المنطق:
- يتم استدعاء المرح (من حلقة)
- يتم تنفيذ المنطق المرح وفعلت ..
- يعود إلى حلقة
- سيتم استدعاء رد الاتصال في نهاية المطاف، عندما تنتهي 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.