PDA

View Full Version : سوال: عدم کارکرد صحیح دریافت اطلاعات از database در مالتی ترد و سوکت پروگرمینگ



dashti011
یک شنبه 11 بهمن 1394, 15:29 عصر
سلام دوستان، من یه برنامه نوبت دهی دارم که از دو بخش تشکیل شده 1:سرور 2 : کلاینت

سرور : سرور رو به صورت مالتی ترد نوشتم و دیتابیس هم به کمک Entity Framework Code-first ایجاد کردم و از طریق سوکت پروگرمینگ با کلاینت ها در ارتباطه.روش کار به این صورته که کلاینت ها به تعداد نامعین ( از یکی بیشتر) به سرور وصل میشن و در طرف سرور هر کلاینت در ترد جداگانه پردازش میشه و میره اطلاعاتی رو از دیتا بیس میخونه و به هر کلاینت جواب مد نظر رو بر میگردونه یکی از این پردازش ها درخواست نوبت در صف هست که در دیتابیس در جدولی به نام گزارش روزانه ، من یه سری نوبت دارم با فیلد هایی به نام شماره نوبت ، وضعیت
یعنی مثلا نوبت های زیر در دیتا بیس هست ( البته این نمونه خیلی ساده هست ....در عمل متفاوته )

ای دی >شماره نوبت> وضعیت
1> 150 >فراخوانی شده
2 >151 >درصف
3 >152 >درصف
4> 153 >درصف

وقتی کلاینتها همزمان به سرور وصل میشن و درخواست نوبت رو به سرور میدن ، هر کلاینت در یک ترد جدید قرار میگیره و در پردازش میره به سمت دیتا بیس و با کمک دستور FirstOrDefualt میره اولین نوبتی که وضعیت اون " درصف" هست رو پیدا میکنه و به کلاینت میفرسته و قبل از ارسال عدد به کلاینت ، وضعیت نوبت را به نام "فراخوانی شده" تغییر میده ،در 90 درصد مواقع تا این جا که مشکلی نیست ظاهرا، اما مشکل وقتی پیش میاد که وقتی دو یا چند کلانت همزمان درخواست نوبت رو به سرور میفرستن سرور به هر دو کلاینت عدد 151 رو برمیگرونه در صورتی که با درخواست اول باید وضعیت عدد 151 به "فراخوانی شده" تغییر پیدا کنه و به کلاینت اول فرستاده شده باشه و برای کلاینت دوم که قاعدتا با چند میلی ثانیه اختلاف ،درخواست نوبت داده، عدد 152 که در وضعیت "درصف" قرار داره رو برگردونه ولی این اتفاق بعضی وقت ها اشتباه رخ میده و عدد یکسان رو برمیگردونه

اگر لازمه من جدول دیتا بیس و کد رو بذارم ، ممنون میشم منو راهنمایی کنید

Davidd
یک شنبه 11 بهمن 1394, 15:47 عصر
سلام. فرایند خواندن از صف، بروز کردن وضعیت صف و ارسال نتیجه به کلاینت ناحیه بحرانی هستند چون از یک منبع مشترک استفاده می شود بنابراین نباید اجازه داد دو ترد همزمان وارد ناحیه بحرانی شوند (انحصار متقابل). برای این کار میتونی از دستور lock استفاده کنی تا فقط یک ترد در آن واحد بتونه وارد ناحیه بحرانی بشه.

hamid_hr
یک شنبه 11 بهمن 1394, 16:27 عصر
شما فک کنم یک عدد رو میاین میخونین برا کلاینت میفرستین و بعد عدد رو یک دونه زیاد میکنین برا نفر بعدی
خب باید از زمانی که این مرحله درخواست شماره برا کلاینت اغاز میشه اون متغییر رو با دستور lock که دوستمون فرمودند قفل کنین
و اگه جایی دیگه بخواد به این متغییر دسترسی داشته باشه منتظر میمونه تا کار کلاینت اول تموم بشه
اینطوری اون مساله ناحیه بحران حل میشه

dashti011
دوشنبه 12 بهمن 1394, 19:17 عصر
برای این کار میتونی از دستور lock استفاده کنی تا فقط یک ترد در آن واحد بتونه وارد ناحیه بحرانی بشه. ممنون نتیجه را تست میکنم همینجا میگم


شما فک کنم یک عدد رو میاین میخونین برا کلاینت میفرستین و بعد عدد رو یک دونه زیاد میکنین برا نفر بعدی
نه در هر ترد من اولین عدد با وضعیت "درصف" رو پیدا میکنم و وضعیت اونو به "فراخوانی شده" تغییر میدم و شماره نوبت رو میدم به کلاینت

dashti011
دوشنبه 12 بهمن 1394, 20:33 عصر
مشکل من به صورت زیر حل شد ،البته یجورایی من کد رو نوشته بودم اما هندل نکرده بودم داستان از این قراره که برای رفع این مشکل باید از اتریبیوت
[Timestamp] استفاده کنید و کد زیر را به جدول خودتون اضافه کنید مثل زیر



[Timestamp]
public byte[] RowVersion { get; set; }



با کمک این پراپرتی ، خود دیتا بیس با هر بار ویرایش و تغییرات در یک ردیف ، مقداری پراپرتی rowversion اتوماتیک تغییر میکنه
، پس وقتی شما میخوان یک ردیف رو ویرایش کنید موقع باز کردن جدول و ردیف مورد نظر مقدار rowversion نیز خونده میشه و موقع ویرایش ( تغییرات)
دوباره مقدار این ستون با مقدار قبلی مقایسه میشه و در صورتی که تفاوت داشته باشه یعنی این ردیف جدول از زمانی که خونده شده تغییر کرده ( توسط یوزر دیگه) پس exeption مربوط به
Concurrency رخ میده و اگر شما کدتون رو توی try بذارید میتونید با catch (DbUpdateConcurrencyException ex) کد را هندل کنید و متوجه بشید این ردیف تغییر کرده و برید ردیف دیگری رو بخونید

Helpco
سه شنبه 13 بهمن 1394, 15:49 عصر
سلام
امکان داره یک نمونه کوچیک از برنامتون اینجا قرا بدید
ممنون میشم اگه این کار بکنید
مخصوصن قسمت صف برنامه را