מאמרים בנושא ‏C++‎‏‏.

CppCMS עובר מ-LGPLv3 ל-MIT

ב־יום שלישי, 16 בינואר 2018, מאת ארתיום; פורסם תחת: תכנה חופשית, לינוקס, פיתוח, תכנה ומחשבים, CppCMS, C++‎‏; ‏0 תגובות

היום עדכנתי רישיון של CppCMS ל-MIT. הגרסה הקרובה 1.2 תשוחרר עם רישיון מעודכן

ההחלטה נובעת ממספר סיבות:

  1. רצון להגדיל נתח השוק של CppCMS ולהקל על כניסה של משתמשים חדשים
  2. להביא יותר מפתחים לפרויקט

אחרי תקופה ארוכה שוחררה בטא של CppCMS 1.1.0

ב־יום רביעי, 12 ביולי 2017, מאת ארתיום; פורסם תחת: תכנה חופשית, פיתוח, CppCMS, C++‎‏; ‏0 תגובות

אחרי תקופה ארוכה של המתנה שוחררה גרסת בטא 1.1.0 של CppCMS. גרסה זו מכילה המון שיפורים ושיוניים. ביניהם:

  • תכנון מחדש של application pool לתיקון מספר בעיות מובנות שהיו קיימות בו עד כה
  • API חדש של פעולות non-blocking לשיפור משמעותי בביצועי אפליקציות אסינכרוניות
  • סיכון ועיבוד בזמן העלאה של התוכן (למשל עיבוד או בדיקה של קבצים תוך כדי העלאה)
  • תמיכה משופרת ב-RESTful API
  • מערכת לניהול plugin ושיפורים מערכת תבניות (templates) בהם.
  • אפשרות ניהול session ללא עוגיות (למקרה והמשתמש ממש צריך)
  • שילוב ניהול ה-session מול טכנולוגיות אחרות כולל מימוש עבור PHP, Java Servlet, ASP.Net ו-Python Django
  • שיפורי ביצועים רבים
  • ועוד...

התכנון הוא לבצע בדיקת בטא מהירה, לשחרר 1.2 כגרסה יציבה (גם ככה חלק ניכר מהמשתמשים כבר עובד בענף הפיתוח ב-git).

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

  • ל-1.4 תמיכה מלאה ב-HTTP/1.1, ב-HTTPS ומימוש של websockets
  • ל-2.0 להעביר CppCMS ל-C++11 תוך ניקוי חלק מה-API שילקח מספריה סטנדרטית כמו std::shared_ptr

אתם מוזמנים להתנסות בגרסת בטא האחרונה!

שילוב בין טכנולוגיות Web שונות ו-CppCMS

ב־יום שני, 16 בנובמבר 2015, מאת ארתיום; פורסם תחת: תכנה חופשית, פיתוח, CppCMS, C++‎‏, Java; ‏8 תגובות

כשיש לך מערכת ווב גדולה ומפותחת ואתה צריך להעביר חלקים קריטיים ממנה לטכנולוגיה מהירה יותר (קרי CppCMS) אתה נתקל קודם כל בבעיה הבסיסית - איך לשתף מידע.

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

לכן, יצרתי שכבת תיאמות שמאפשרת לגשת ל-Session של CppCMS מכל שפת תכנות אחרת.

בשלב ראשון עדכנתי את המחלקות הקשירות לניהול ה-Session של CppCMS שיוכלו לפעול בצורה בלתי תלויה מהמערכת. יצרתי API נקי מבוסס C בלבד כדי שלא יהיו בעיות כמו חריגות (exceptions) האופייניות ל-++C וגם כדי שאפשר היה לטעון את הפונקיות ישירות בעזרת dlopen.

אחר כך יצרתי מספר מודולים עבור שפות שונות:

  • PHP עם שימוש ב-Swig
  • Java/Servlet עם שימוש ב-JNA
  • Python עם שימוש ב-ctypes והתממשקות עם Django (אבל לא מוגבל ל-Django)
  • Asp.Net עם שימוש ב-PInvoke

כמובן זה לא מוגבל אליהם בלבד. אבל לכל שפה חדשה צריך לבנות מעטפת. שקלתי לעשות גם ל-Ruby on Rails אבל ויתרתי לבינתיים כי אין לי ניסיון עם Ruby בכלל, אז שמישהו יתרום בעת הצורך.

חייב להגיד לכל טכנולויה היו בעיות משלה... למשל ב-Python היו התנהגויות מוזרות כשניסיתי לבנות מתודות באופן דינאמי, ב-Java/JNA הכל עבר חלק להבפליא. PInvoke שיגע אותי עם חוסר רצון שלו להמיר UTF-8 ל-string ובחזרה (אגב Mono כן עושה זאת בצורה שקופה אבל לא Net. של Windows מתעקש להשתמש בקידוד ANSI). יצירת מודולים עם Swig עבדה לא רע בכלל, אבל נדרשת עוד מעטפת כדי להתאים את הכל בסופו של דבר לשפה עצמה והתנהגותה.

ואיך זה נראה

PHP:

// pool initialization
$pool=CppCMS_SessionPool::from_config('cppcms-config.js');
// per request session access
$session=$pool->session();
$session->load();
$x=0;
if($session->is_set('x')) {
        $x=$session['x'];
}

$x=intval($x)+1;
$session['x']=$x;
$session->save();
...

Java/Servlet:

static SessionPool pool;

public void init() throws ServletException
{
    pool = SessionPool.openFromConfig("/path/to/cppcms-config.js");
}

public void doGet(HttpServletRequest request,
                  HttpServletResponse response) 
                    throws ServletException, IOException
{
    Session session = pool.getSession();
    session.load(request);
    String x="0";
    if(session.isSet("x"))
        x=session.get("x");
    x=Integer.toString(Integer.parseInt(x)+1);
    session.set("x",x);
    session.save(response);
    session.close();
    ...
}

Python/Django:

# Create global pool
pool=cppcms.SessionPool('/path/to/cppcms-config.js')

# Actual view
def home(request):
    s=pool.session()
    s.load(django_request=request)
    v='0'
    if 'x' in s:
            v= s['x']
    s['x']=str(int(v)+1)
    response = HttpResponse()
    s.save(django_response=response)
    ...

C#/ASP.Net:

static SessionPool pool;
static Example() {
    pool = SessionPool.FromConfig("cppcms-config.js");
}
protected void Page_Load(object sender,EventArgs e)
{
    using(Session s = pool.Session()) {
        s.Load(Request);
        string v="0";
        if(s.IsSet("x"))
            v=s["x"];
        v = (int.Parse(v) + 1).ToString();
        s["x"]=v;
        s.Save(Response);
    }
    ...
}

אפשר לראות את הקוד והדוגמאות המלאות כאן

אני עדיין תוהה עם איזו עוד פלטפורמה כדי לעשות אינטגרציה. בסופו של דבר חשובה לי הפשוטות והנוחות של העבודה.

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

ב־יום רביעי, 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.

כיצד לא לעשות יוניקוד

ב־יום ראשון, 29 באפריל 2012, מאת ארתיום; פורסם תחת: תכנה חופשית, פיתוח, תכנה ומחשבים, C++‎‏, Unicode; ‏0 תגובות

הסיפורו של הניסיון להדפיס "שלום" במספר שפות במסוף של חלונות.

http://blog.cppcms.com/post/105

העמוד הבא

דפים

נושאים