جعل المتغيرات الساكنة العالمية متعددة القراءة آمنة
-
27-09-2019 - |
سؤال
لديّ متغيرات ثابتة عالمية في مكتبة C ، والتي تولد استثناءات في تشغيل Multithread. أحتاج إلى جعلها آمنة بطريقة ما (أي ، يجب أن يرتبط كل مؤشر ترابط بمثيل مختلف لهذه المتغيرات). أي طرق موصى بها؟
المحلول
لا توجد طريقة قياسية تعمل في جميع تطبيقات C ، ولكن توجد حلول خاصة بالتنفيذ. على سبيل المثال ، مع برنامج التحويل البرمجي لشركة Microsoft (انظر المستندات),
__declspec( thread ) int tls_i = 1;
يصنع tls_i
Live in Thread-Local Storage (كل مؤشر ترابط له مثيل منفصل خاص به لهذا المتغير). مع مجلس التعاون الخليجي, بناء الجملة
__thread int tls_i;
قد ترغب أيضًا في التحقق من دخول ويكيبيديا حول هذا الموضوع.
نصائح أخرى
السؤال الأول:
- هل تحتاج المواضيع إلى نسخها الخاصة من المتغيرات؟
- أو هل يحتاجون إلى تنسيق الوصول إلى نسخة مشتركة واحدة؟
إذا كنت بحاجة إلى السابق ، فقد قدمت الإجابات الأخرى اقتراحات حول "تخزين الخيط المحلي".
إذا كنت بحاجة إلى هذا الأخير ، فأنت بطريقة ما أو لآخر تحتاج إلى التأكد من وجود طفرات مناسبة على تلك المتغيرات (نطاق Mutex هو أحد المشكلات التي تواجهها) ، وأن جميع الخيوط تستخدم Mutex ، وتحرير Mutex. هذا أصعب. قد تكون بحاجة إلى توفير وظائف تتحكم في الوصول إلى المتغيرات.
المتغير القياسي errno
يمكن أن يكون lvalue قابلة للتعديل:
extern int *_errno_func(void);
#define errno (*(_errno_func)())
في تطبيق ملولب (تم تجميعه باستخدام -dreentrant) ، هذا ما يحدث ؛ على MacOS X ، يبدو أنه ما يحدث على أي حال (يستخدمون الاسم __error
بدلاً من _errno_func
; ؛ كلاهما في مساحة اسم التنفيذ).
قد ترغب في القيام بشيء مماثل ، أو ينتهي بك الأمر إلى القيام بشيء مشابه لمتغيراتك. حقيقة أنك تقول أنها ثابتة يحسن الأمور قليلاً. لديك ملف واحد فقط للتعامل معه (ما لم تكن مهملًا بما يكفي لتمرير - أو على مؤشرات لتلك المتغيرات).
ما تحتاجه هو TLS (موضوع تخزين محلي), ، وهو المعروف أيضًا باسم بيانات محددة أو البيانات الخاصة بالاتصالات. يمكن أن تضمن هذه الآلية كل مؤشر ترابط للوصول إلى نسخة منفصلة من البيانات ، دون القلق بشأن مزامنة الوصول مع مؤشرات الترابط الأخرى.
هناك طريقتان لاستخدام TLS:
ضمنيًا: استخدام الكلمة الرئيسية
شبابيك: __declspec (thread) int tls_var = 10 ؛
Linux مع GCC: __thread int tls_var = 10
صريح: استخدام واجهة برمجة تطبيقات TLS محددة
شبابيك:
- tlsalloc (): تخصيص الذاكرة لبيانات TLS
- tlsfree (): تحرير ذكرى بيانات TLS
- tlssetvalue (): اضبط قيمة TLS
- tlsgetValue (): احصل على قيمة TLS
يرجى الرجوع إلى MSDN للحصول على معلومات مفصلة.
Linux مع GCC:
- pthread_key_create (): إنشاء بيانات TLS
- pthread_key_delete (): مصير بيانات TLS
- pthread_getspecific (): احصل على قيمة TLS
- PTHREAD_SETSPecific(): تعيين قيمة TLS
معظم المترجمين لديهم طريقة لتخزين الخيوط المحلية. على افتراض أنه متاح ، هذا ما تريده.