כשעפים על מספר מעבדים

ב־8.8.2012, מאת ארתיום; פורסם תחת: תכנה חופשית, תכנה ומחשבים, C++‎‏; ‏4 תגובות

לפני כמה ימים קיבלתי דיווח, שתוכנה פשוטה שעובדת עם CppCMS עפה ב־FreeBSD כשיוצרים עומס. קיבלתי trace של המחסנית, שהיה נראה חשוד ומוזר. ניסיתי לשחזר... הכל היה תקין.

אז הופנית לדיווח על באג ישן וסגור שנראה כשתי טיפות מים דומה לתעופה הזו. אז הבנתי שבכל זאת מדובר במשהו אמתי. פתחתי VirtualBox, הורדתי image של FreeBSD 9.0/64bit ותוך עשר דקות התחלתי לנסות שוב. ללא הועיל. ואז קיבלתי תוכנה שלדוגמה (טריביאלית לחלוטין) שבאמת עפה!

מעמיסים עליה כמה אלפי פניות ומידי פעם אני מקבל תעופה בפניה לאובייקט std::locale - האובייקט שמחזיק מידע על לוקל המערכת ובפרט הקידוד שלה (כדי להוסיף ל־content-type).

צללתי פנימה והתחלתי לחפור - זה היה נראה כמו באג שקשור ל־threading, ניסיתי גרסאות קומפיילר שונות ואופציות שונות - תעופה היה קבועה וברורה.

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

פה נדלקה לי מנורה אדומה - משהו לא בסדר ב־reference-counting, קרי הוא לא מתבצע בצורה אטומית. הכנתי תוכנית לבדיקה שהעתיקה את האובייקט מיליוני פעמים ממספר חוטים - הכל תקין.

נכנסתי עוד יותר פנימה והתחלתי להדפיס את המונה (שהוצאתי בדרך לא דרך כי הוא private) ואכן - הוא ממש לא יציב, הולך וגדל עם הזמן - קרי, קיבלתי אמות - יש בעיה במונה!

המשכתי לחפור עוד יותר לעומק והגעתי לקוד שמבצע את עדכון המונה ב־‎libstdc++‎:

if (__gthread_active_p())
  __atomic_add(__mem, __val);
else
  __atomic_add_single(__mem, __val);

כאשר המטרה של הקוד היא - אם אנחנו רצים מחוט אחד - אז אפשר לבצע חיבור פשוט וזול, אחרת מנהלים עדכון מונה בצורה אטומית - נכנסתי עם gdb בקוד לדוגמה וגיליתי:

  • אם אני לא עושה קישור עם libpthread - הוא תמיד מריץ קוד עבור מערכת עם חוט יחיד.
  • אחרת תמיד מבצע פעולה אטומית.

מה הבעיה? הספרייה שלי קשורה ישירות ב־libpthread, אבל התכנה הראשית לא! בלינוקס זה לא מפריע אבל ב־FreeBSD זה לא עובד!

אז הוספתי דגלון ‎-lpthread‎ לתכנה הראשית והבעיה נפתרה ב־100% - המונה הפך ליציב ומתאפס מתי שצריך.

כנראה צריך ללכת לחברה ב־FreeBSD או ב־GCC ולפתוח באג: אם התכנה הראשית לא צריכה להפעיל חוטים באופן ישיר זה לא אומר שהספריות לא עובדות עם החוטים!

זה גם הסביר לי מדוע אותו באג שנסגר בגלל שלא היה ניתן לשחזר אותו, לא השתחזר - כי הבעיה נפתרה כנראה במקרה ע"י קישור ל־libpthread.

כך או אחרת, שמחתי שמצאתי את הבעיה, אפילו שהוא ממש לא הבעיה של ה־framework.

תגובות

ik, ב־9.8.2012, 12:37

שאלה. ב FPC ממליצים לך לעבוד עם יחידה בשם cthreads (זה עדיין לא משתמש ב pthreads) ביוניקס (בכלל), כאשר יש משהו שהוא multi threaded אצלך. אולי הפתרון עבורך הוא המלצה לעשות משהו דומה ?

ארתיום, ב־9.8.2012, 12:58

אני לא כל כך מבין למה אתה מתכוון:

http://www.freepascal.org/docs-html/rtl/cthreads/index.html

לפי זה כתוב שזה משתמש ב-POSIX Threads.

או למה אתה מתכוון - הם משתמשים במימוש משלהם עבור threading?

בגדול, ההמלצה צריכה להיות (ככל הנראה לעשות קישור ישיר לספריית pthreads גם אם אתה לא קורא לפונקיות pthreads ישירות.

ik, ב־10.8.2012, 0:03

הם לא יוצרים מנהל משלהם. הגישה בכללותה אומרת שיש לך API מסויים, ואתה בוחר מה הוא מריץ למטה יותר. ככה אתה יכול לשנות רק את המנוע, בלי לשנות את הקוד שלך.

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

http://wiki.freepascal.org/Multithreaded_Application_Tutorial

ארתיום, ב־11.8.2012, 15:15

אם כך אני ממש לא מבין למה אתה התכוונת כשכתבת:

ב FPC ממליצים לך לעבוד עם יחידה בשם cthreads (זה עדיין לא משתמש ב pthreads) ביוניקס (בכלל)

הוסף תגובה:

 
 כתובת דוא"ל לא תוצג
 

ניתן לכתוב תגובות עם שימוש בתחביר Markdown.

חובה לאפשר JavaScript כדי להגיב.

דפים

נושאים