سلام
از async await استفاده کنید :
هنگ برنامه هنگام گرفتن سورس سایت
اما در اون مثال ، 2 نکته را جایگزین کنید :
اول اینکه سعی کنید بجای اون بخش از کد که در نخ جدید اجرا میشه را داده بودم ، یعنی بجای کد زیر در اون مثال :
Task<string> httpDataTask = new Task<string>(new Func<string>(this.GetHttpData));
httpDataTask.Start();
از متدهای TaskFactory.StartNew یا از متد استاتیک Task.Run برای اجرای کدتوی در نخ جدید استفاده کنید :
TaskFactory.StartNew Method (System.Threading.Tasks) | Microsoft Learn
دوم و مهمتر اینکه سعی کنید این تیکه از کدها را وقتی بکار میبرید ، درون متدی بکار ببرید که نوع بازگشتی اش از Task یا Task<T> باشه .
یعنی مثلِ اون مثال ، مستقیما کد بالا را درون رویداد ها (که خروجی ای ندارند و void هستند) ، بکار نبرید .
چون حداقل اینکه برای مدیریت استثنا و خطاهایی که درونِ اون نخِ جدید اتفاق میافته ، نوع خروجی Task یا Task<T> بکار میاد .
برای مدیریت استثنا و خطاها در نخ جدید هم به لینک زیر مراجعه کنید :
مدیریت استثناء در نخ جدید
برای اینکار (طبق مثال در لینک بالا) ، کافی هست که بخش await را درون try catch بذارید . اونجایی این کار را میکنید هم توی متدی باید باشه که خروجی اش از نوع Task یا Task<T> باشه .
----------
یه مثال از این نکات بالا :
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
long fibonacciValue = await this.FibonacciAsync(37);
// کد مورد نظرتون برای اینکه بعد از اتمامِ اجرای نخ جدیدتون ، اجرا بشه را اینجا ، یعنی در پایینِ await بنویسید .
if (fibonacciValue > -1)
MessageBox.Show(fibonacciValue.ToString());
}
private async Task<long> FibonacciAsync(int number)
{
Task<long> fibonucciTask = Task.Factory.StartNew<long>(new Func<object, long>(this.Fibonacci), number);
long fibonucciReturnValue = -1;
try
{
fibonucciReturnValue = await fibonucciTask;
// کد مورد نظرتون برای اینکه بعد از اتمامِ اجرای نخ جدیدتون ، اجرا بشه را اینجا ، یعنی در پایینِ await بنویسید .
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
}
return fibonucciReturnValue;
}
private long Fibonacci(object number)
{
int numberConverted = Convert.ToInt32(number);
if (numberConverted == 0 || numberConverted == 1)
return numberConverted;
return this.Fibonacci(numberConverted - 1) + this.Fibonacci(numberConverted - 2);
}
که خروجیِ await را مستقیما میتونید به عنوان مقدار long در مثال بالا ، برگردونید .
یعنی اگه متدی هم فقط از نوع Task باشه (یعنی Task<T> نباشه) ، دیگه اصلا return کردن ، لازم نداره .
میشه در این سلسله مراتبی هم یه متدی باشه که فقط Task باشه و یعنی هیچ چی برنگردونه .
یعنی مثلا رویداد کلیک در بالا ، یه متدی دیگه ای که در مثال بالا نیست و فرضا اسم اش MiddleMethod باشه که خروجی اش از نوع Task باشه (نه از نوع Task<T> یا Task<long>) را فراخوانی کنه .
بنابراین این متد ، اصلا نیاز به استفاده از کلمه ی کلیدی return در بدنه اش نداره (ربطی به استفاده نکردن از کلمه ی کلیدیِ await نداره و باید ازش استفاده کنه . در واقع توصیه ی اکید میشه که تمام متدهایی که async هستند ، درون شون از await استفاده کنند) .
و این متدِ MiddleMethod ، درون خودش ، متدِ FibonacciAsync در مثال بالا را فراخونی کنه که بقیه ی روال هاش مشخص هست .
متد FibonacciAsync در بالا را بصورت خلاصه به شکل زیر هم میشه نوشت منتها در این حالت ، نمیشه از try catch درش استفاده کرد یا بعد از await اش ، کدی نوشت تا بعد از خاتمه ی اجرای نخ جدید ، اون کد اجرا بشه :
private async Task<long> FibonacciAsync(int number)
{
return await Task.Factory.StartNew<long>(new Func<object, long>(this.Fibonacci), number);
}
---------
await هم کارکردش به این صورت هست که وقتی کنترل برنامه ، به کلمه ی کلیدی await میرسه ، اون Task ئه اجرا شده ای که بهش داده شد را منتظرش میمونه تا اجراش تمام بشه و بنابراین کدهایی که در پایینِ اش نوشته شدن را معلق میذاره (یه کاری شبیه به yield ها) و این کدها اجرا نمیشن تا اون Task خاتمه پیدا کنه ،
و مخصوصا اینکه همچنین کنترلِ اجرای کدها را به استکِ متدِ قبلی هدایت میکنه (یعنی متد قبلی توی استک که فراخوانی کننده ی این متدی بود که توی این متد ، کلمه ی کلیدیِ await وجود داشت ، کنترلِ اجرای کدهای برنامه را به اون استکِ قبلیِ متد در اون نخ میبره) .
یعنی کاری شبیه به return انجام میده (البته از لحاظ برگشتن به استک قبلی ، شبیه بهش هست وگرنه ادامه ی کدهاش بعد از خاتمه ی نخ اجرا میشه که این ، کار را return انجام نمیده) .
-----------
برای مدیریت دسترسی به داده ی واحد (مثلا دسترسی به متغییر سراسری ، یا دسترسی به متغییر محلی ای که اشاره گری به متغییر سراسری هست) درون دو یا چند نخ هم روش های متفاوتی که هر کدوم برای جایی کاربرد دارن ، هست اما یکی از رایج ترین شون ، استفاده از کلمه ی کلیدی lock هست .