דילמת נעילת Singleton

בטיטi

New member
דילמת נעילת Singleton

נניח ויש לי את הסינגלטון הבא :
public class JobsMAnager { private static JobsMAnager m_Current; public static JobsManager Current { get { if (m_Current == null) { m_Current = new JobsManager (); } return m_Current; } } }​
יש כאן בעיה, במידה ו 2 משתמשים יגשו בו זמנית בדיוק, יווצרו 2 מופעים של האובייקט. ניתן להוסיף Lock מעל התנאי, אבל אז פשוט העברנו את אותה הבעיה שורה אחת מעלה. יצא לי לראות קוד שמשתמש ב Lock מקונן, אבל גם שם לדעתי קיימת אותה בעיה בדיוק. כיצד מתמודדים ? (אולי ממתינים פרק זמן רנדומלי לפני נעילת הקטע הקריטי ?)
 

arnonrgo

New member
ב#C

צריך רק private static readonly Singleton instance = new Singleton(); הCLR דואד להכל בJava (לפחות גרסאות לפני 1.5) היה צריך double check ארנון
 

בטיטi

New member
תגובה :

1. ב #C - אבל אם 2 ניגשים בדיוק באותו הרגע ? 2. ב JAVA, איך בדיקה כפולה היתה עוזרת ?
 

arnonrgo

New member
link

הכל מוסבר לא רע ב http://msdn2.microsoft.com/en-gb/library/ms998558.aspx
 

בטיטi

New member
תודה, אבל לדעתי הם לא מתמודדים עם

הבעיה ששניים נגשים בדיוק באותו הזמן ליצירת אובייקט.. (גם הנעילה לא פותרת)
 

arnonrgo

New member
אם אתה לא מאמין

אז אין לי מה לעשות אבל מיקרוסופט אומרים שהם פותרים את זה ברמת הCLR ברמה של שימוש בlock (שוב ב#C ) צריך להגדיר את המשתנה volatile (גם זה מוסבר בלינק) כדי להבטיח שהמשתנה יסיים אתחול לפני שיהיה זמין אולי ההסבר כאן יהיה יותר מובן: http://www.yoda.arachsys.com/csharp/singleton.html אגב, אם אנחנו כבר בנושא באופן עקרוני כדאי מאד למעט בשימוש בsingletons באותה מידה שאנחנו לא משתמשים במשתנים גלובאלים אחרים
 

בטיטi

New member
זה לא עניין של אמונה, אלא של ביטים.

פשוט לא ברור לי איך הם מונעים מצד שבאותה מילי שניה 2 משתמשים מנסים לגשת בפעם הראשונה לאובייקט, ואז בעצם הוא יאותחל פעמיים.
 

arnonrgo

New member
דווקא כן

אם מסבירים לך שהקוד בהמשך עובד רק בגלל שיש פה שימוש בvolatile אז או שאתה מאמין שvolatile דואג לגך שלא יהיו אופטימיזציות הקשורות לthread אחד או שאתה לא מאמין לתעוד אם אתה מאמין שהתעוד נכון אז אתה יכול להבין שהערך של instance לא ישתנה כבר בזמן הבדיקה שניה אם אתה לא מאמין שvolatile עושה מה שהתעוד של מיקרוסופט עושה אז יכול להיות מצב שהוא בדיוק בשינוי - אתה ראשי כמובן לקמפל עם ngen ולעבור על האסמבלר (אני לפחות לא הרגשתי צורך לזה) בצורה דומה לגבי השימוש ב internal static readonly Singleton instance = new Singleton();
using System; public sealed class Singleton { private static volatile Singleton instance; private static object syncRoot = new Object(); private Singleton() {} public static Singleton Instance { get { if (instance == null) { lock (syncRoot) { if (instance == null) instance = new Singleton(); } } return instance; } }​
 

טלד

New member
כמה אפשרויות שאני מכיר

עד כמה שאני מבין בעיית הנעילה היא תמיד ניתנת לפתרון עד כדי dead zone של פקודת אסמבלר אחת... יש 2 פתרונות שאני נוהג להשתמש בהם: 1. להוסיף לקלאס משתנה מסוג bool m_bIsInited. ולעשות משהו בסגנון של:
if (!m_bIsInited) { m_bIsInited = TRUE; m_Current = new JobsManager (); } while(!m_Current) { } return m_Current​
ככה האזור המסוכן שלך יורד לשורה אחת, והוא לא כל הזמן שלוקח לקונסטרקטור. בפתרון כזה אני משתמש אפילו כשהמערכת לא דורשת סנכרון, כי הוא לא מסורבל לעומת מה שכתבת. אפשרות שניה, שאותה אני אוהב יותר - לאתחל את האובייקט מראש, בעליית התוכנה (במידת האפשר) או למצוא איזה זמן שבו אין סיכון להתנגשות, או לאפשר רק לאובייקט אחד להיות זה שמאתחל את הסינגלטון - אבל אז אם יגשו אליו אחרים לפני כן - הם יקבלו NULL. אני אשמח לשמוע עוד דעות בנושא...
 

מתכNET

New member
לא ברור לך שזה לא מגן?

אז נכון שזה יעבוד ב 99% מהמקרים הבעיה שב 1% הנותר זה קוד שיעבוד בטיל החץ....
 

טלד

New member
זה יעבוד בהרבה יותר מ-99%

וכמו שכתבתי, השאלה היא מה האפליקציה... אם יש לך רעיון יותר טוב, אולי תכתוב אותו?
 
Nil ref error

הקוד הזה לא יעבוד ב Multi thread שני threads שמגיעים ל IF באותו רגע יאתחלו את המשתנה פעמיים. ע"פ השפה נראה שזה C++ ככה שיש גם זליגת זכרון. מעבר לכך, מה המטרה של ה while - חוץ מלתקוע את האפליקציה אם אין לך זכרון?
 
למעלה