مرتب سازی حافظه

از ویکی‌پدیا، دانشنامهٔ آزاد

"این مقاله در حال ترجمه از ویکی انگلیسی است، لطفا حذف نشود." ترتیب حافظه ، ترتیب دسترسی به حافظه کامپیوتر را توسط پردازنده بیان می کند. همچنین می تواند به ترتیب حافظه ی تولید شده توسط کامپایلر در زمان کامپایل و یا ترتیب حافظه تولید شده توسط پردازنده در زمان اجرای برنامه، اشاره کند. در ریزپردازنده های مدرن، ترتیب حافظه توانایی های پردازنده را برای مرتب کردن مجدد دستور های حافظه، دسته بندی می کند. ( یک مدل از اجرای خارج از ترتیب). مرتب کردن مجدد می تواند برای بکار گیری کامل از پهنای باند گذرگاه در حافظه های مختلف مانند حافظه نهان و بانک حافظه، استفاده شود. در اکثر تک پردازنده های مدن، دستور های حافظه به ترتیبی که کد برنامه تعیین می کند، اجرا نمی شود. در برنامه های تک رشته ای، تمام اجرا های خارج از ترتیب از دید برنامه نویس پنهان می شوند در نتیجه این طور به نظر می آید که همه ی دستور ها در ترتیب تعیین شده، اجرا شده اند. در برنامه های چند رشته ای، مورد ذکر شده می توند سبب بروز مشکل هایی شود، در جهت جلوگیری از بروز این مشکل، می توان از موانع حافظه استفاده کرد.

مرتب سازی حافظه در زمان کامپایل[ویرایش]

اکثر زبان‌های برنامه‌نویسی ایده ای از یک رشته اجرا دارند که دستورها را به ترتیب تعریف‌شده اجرا می‌کند . کامپایلر های سنتی دستور های سطح بالا را به دنباله ای از دستورالعمل ها ترجمه می کنند که این دستورالعمل ها در سطح ماشینی زیرین به شمارنده برنامه مرتبط هستند. تاثیر اجرایی در دو مرحله قابل رویت است:

  1. در کد برنامه در سطح بالا و در سطح ماشین ( مانند زمانی که در برنامه نویسی همزمان توسط رشته ها یا عناصر پردازشی دیده می شود).
  2. در زمان اشکال زدایی ( یک سخت افزار اشکال زدایی با دسترسی به وضعیت های ماشین این کار را انجام می دهد).

ترتیب حافظه زمان کامپایل به مورد اول مربوط می شود.

مسائل کلی دستور برنامه[ویرایش]

تاثیر نظم برنامه ی ارزیابی عبارت[ویرایش]

در طول زمان کامپایل، دستورالعمل های سخت افزاری معمولا دقیق تر از آنچه که در کد سطح بالا مشخص شده است، تولید می شوند. اولین تاثیر قابل مشاهده در برنامه نویسی رویه ای، تخصیص یک مقدار جدید به یک متغیر نامگذاری شده است.

;sum = a + b + c 
;print(sum)

دستور print، دستوری را که در آن به متغیر sum مقدار تخصیص داده شده است را دنبال می کند. وقتی که print به مقدار محاسبه شده متغیر sum ارجاع می دهد، نتیجه آن تاثیر قابل مشاهده دنباله اجرا شده قبلی است. طبق قوانین، وقتی print متغیر sum را فراخوانی می کند، مقدار sum باید آخرین مقدار تخصیص یافته به این متغیر باشد. در سطح ماشین , تعداد کمی از ماشین ها می توانند دستور های جمع را برای سه عدد به طور همزمان و در یک دستورالعمل واحد انجام دهند؛ پس کامپایلر باید این عبارت را به دو دستور متفاوت ترجمه کند. اگر مفاهیم زبان برنامه، کامپایلر را محدود به ترجمه (برای مثال) چپ-به-راست کند، کدی که تولید می شود مانند این است که برنامه نویس دستورهای زیر را در برنامه اصلی نوشته باشد:

;sum = a + b
; sum = sum + c

اگر کامپایلر اجازه استفاده از خاصیت شرکت پذیری جمع را داشته باشد، کد زیر تولید می شود:

;sum = b + c 
;sum = a + sum 

اگر کامپایلر مجاز به استفاده از خاصیت جابه‌جایی جمع باشد , ممکن است کد زیر تولید شود :

;sum = a + c 
;sum = sum + b 

باید توجه داشت که در اکثر زبان های برنامه نویسی ، داده عدد صحیح فقط از جبر برای اعداد صحیح ریاضی در غیاب سرریز عدد صحیح استفاده می کند. همچنین در اغلب زبان های برنامه نویسی، محاسبه ممیز شناور در داده های اعشاری قابل جایگزینی با گرد کرد عدد نیست. اگر برنامه نویس نگران سرریز عدد صحیح و یا تاثیر گرد کرد در اعداد اعشاری باشد، ممکن است برنامه مشابه در سطح بالا به صورت زیر باشد:

;sum = a + b 
;sum = sum + c 

تاثیر ترتیب برنامه شامل فراخوانی تابع[ویرایش]

تعداد زیادی از زبان ها ، مرز دستور را بعنوان نقطه دنباله تلقی می کنند و اجبار می کنند که اثر یک دستور، قبل از اجرای دستور بعد کامل شوند. این مورد کامپایلر را مجبور می کند که کدی مطابق با ترتیب بیان شده تولید کند که در اغلب موارد شامل دستورهای پیچیده ایست و ممکن است شامل فراخوانی تابع درونی باشد.

;sum = f(a) + g(b) + h(c)

در سطح ماشین، فراخوانی یک تابع معمولاً مستلزم تنظیم یک قاب پشته ای برای فراخوانی تابع است که شامل خواندن و نوشتن بسیاری در حافظه ماشین است. در اکثر زبان های کامپایل شده، کامپایلر آزاد است تا تابع f، g و h را به دلخواه خود ترتیب دهد و در نتیجه برنامه را دوباره مرتب کند. در یک زبان کاملاً کاربردی،تاثیر گذاشتن بر روی وضعیت برنامه قابل مشاهده توسط فراخوانی تابع ممنوع است (غیر از مقدار بازگشتی)، و تفاوت در ترتیب حافظه ماشین به دلیل ترتیب فراخوانی تابع برای معناشناسی برنامه بی‌اهمیت خواهد بود. در زبان‌های رویه‌ای، توابعی که نامیده می‌شوند می‌توانند اثر جانبی داشته باشند، مانند انجام دستور های ورودی/خروجی یا به‌روزرسانی متغیرها در محدوده جهانی برنامه، که همگی اثر قابل مشاهده بر روی مدل برنامه دارند. برنامه نویسانی که به چنین جلوه هایی اهمیت می دهند می توانند برنامه منبع اصلی را با دقت بیشتری بیان کنند. مجدداً، برنامه نویس که به این اثر توجه دارد، می تواند در دستور های برنامه اصلی سختگیرتر شود:

;sum = f(a)
;sum = sum + g(b)
;sum = sum + h(c) 

در زبان های برنامه نویسی که مرز دستور ها به عنوان نقاط دنباله تعریف می شوند، فراخوانی های تابع f، g، h باید به ترتیب دقیق اجرا شوند.

مسائل خاص نظم حافظه[ویرایش]

جلوه های ترتیب برنامه شامل دستور های اشاره گر[ویرایش]

حال موردی را در نظر بگیرید که در آن همان عمل جمع با اشاره گر غیرمستقیم بیان شود، مثلا در زبان هایی مثل C/C++:

;sum = *a + *b + *c

عبارت x* یک اشاره‌گر نامیده می‌شود و مکانی از حافظه را که با مقدار فعلی x مشخص شده است، می خواند. اثر خواندن از یک اشاره گر توسط مدل حافظه معماری مشخض می شود. هنگام خواندن از حافظه استاندارد برنامه، به دلیل ترتیب دستور خواندن حافظه، عوارض جانبی وجود ندارد. در برنامه نویسی سیستم های جاسازی شده ، بسیار رایج است که I/O با نقشه حافظه داشته باشیم که در آن دستور های I/O باعث خواندن و نوشتن در حافظه و یا تغییر در حالت عملکرد پردازنده، که عوارض جانبی بسیار قابل مشاهده است، می شود. برای مثال بالا، فرض کنید که نشانگرها به حافظه برنامه منظم بدون این عوارض جانبی اشاره می کنند. کامپایلر آزاد است که این خوانش ها را به نحوی که مناسب می داند، مرتب کند و هیچ عوارض جانبی قابل‌مشاهده برنامه وجود نخواهد داشت. اگر مقدار تخصیص داده شده هم اشاره گر غیرمستقیم باشد چه می شود؟

;sum = *a + *b + *c*

در این قسمت، اینکه زبان به کامپایلر اجازه تقسیم را به صورت زیر بدهد، بعید به نظر می رسد.

// همانطور که توسط کامپایلر بازنویسی شده است
// به طور کلی ممنوع است 
;sum = *a + *b*
;sum = *sum + *c*

این در اکثر موارد ناکارآمد است و نوشتن اشاره گر می تواند اثر جانبی بر روی وضعیت قابل مشاهده ماشین داشته باشد. کامپایلر اجازه این تبدیل تقسیم را نمی دهد، بنابراین تنها نوشته ها در مکان حافظه sum باید به طور منطقی از سه اشاره گر خوانده شده از عبارت پیروی کنند. اما فرض کنید برنامه نویس نگران سرریز اعداد صحیح بوده و این عبارت را در سطح برنامه به صورت زیر تقسیم کند:

// به طور مستقیم توسط برنامه نویس نوشته شده است 
// با نگرانی های دیگر
;sum = *a + *b* 
;sum = *sum + *c* 

عبارت اول دو خوانش حافظه را کد می‌کند , که باید قبل از اولین نامه به sum* باشد ( به هر ترتیب ). عبارت دوم دو خوانش حافظه ( به هر ترتیب ) را کد می‌کند که باید قبل از به روز رسانی دوم sum* باشد. این امر ترتیب دو دستور اضافه را تضمین می‌کند , اما به طور بالقوه یک مشکل جدید برای نام مستعار آدرس را معرفی می کند: هر کدام از این نکته ها می‌توانند به طور بالقوه به مکان حافظه مشابه مراجعه کنند . برای مثال، فرض کنید در این مثال c* و sum* نام مستعار در یک مکان حافظه دارند و هر دو نسخه برنامه را با sum* برای هر دو بازنویسی کنیم.

;sum = *a + *b + *sum*

اینجا هیچ مشکلی وجود ندارد. مقدار اصلی چیزی که ما در ابتدا به عنوان c* نوشتیم در تخصیص به sum* و همچنین مقدار اصلی sum*از بین می‌رود، اما این در وهله اول بازنویسی شده بود و هیچ نگرانی خاصی ندارد.

//چیزی که برنامه با c* و sum* مستعارمی شود 
;sum = *a + *b*
;sum = *sum + *sum* 

در اینجا مقدار اصلی sum* قبل از اولین دسترسی، بازنویسی می شود و در عوض معادل جبری بدست می آید:

// معادل جبریبالا
;sum = (*a + *b) + (*a + *b)* 

که یک مقدار کاملاً متفاوت را به sum* به دلیل تنظیم مجدد دستور ها اختصاص می دهد. به دلیل اثرهای احتمالی، تغییر یافتن مجدد دستورهای اشاره‌گر بدون به خطر انداختن اثرهای برنامه قابل‌مشاهده دشوار است. در حالت معمول، ممکن است هیچ نام مستعاری وجود نداشته باشد، بنابراین به نظر می رسد که کد مانند قبل اجرا شود. اما در حالتی که نام مستعار وجود دارد، خطاهای شدیدتر ممکن است رخ دهد. حتی اگر این موارد به طور کامل در اجرای عادی وجود نداشته باشند، دری را برای یک دشمن مخرب باز می کند تا در جایی که نام مستعار وجود دارد، ورودی ایجاد کند، که منجر به یک سوء استفاده امنیتی از رایانه می شود. ترتیب مجدد امن برنامه قبلی به شرح زیر است:

// یک متغیر محلی موقت 'temp' از نوع مناسب را اعلام کنید 
;temp = *a + *b 
;sum = temp + *c* 

در نهایت حالت غیر مستقیم با فراخوانی تابع اضافه را در نظر بگیرید :

;sum = f(*a) + g(*b)* 

کامپایلر ممکن است ارزیابی اشاره گر های a* و b* را زودتر انتخاب کند، ممکن است ارزیابی b* را به بعد از فراخوانی تابع f یا ارزیابی a* را به بعد از فراخوانی تابع g به تعویق بیندازد. اگر تابع f و g اثر جانبی قابل مشاهده نداشته باشند، هر سه گزینه برنامه‌ای با اثر قابل‌مشاهده مشابه تولید خواهند کرد. اگر پیاده سازی f یا g دارای اثر جانبی هر اشاره‌گر باشد، این سه گزینه می‌توانند جلوه‌های برنامه قابل مشاهده مختلفی را ایجاد کنند.

ترتیب حافظه در مشخصات زبان[ویرایش]

به طور کلی، زبان های کامپایل شده به اندازه کافی دقیق نیستند تا کامپایلر به طور رسمی در زمان کامپایل مشخص کند که کدام اشاره گرها نام مستعار دارند و کدام ها ندارند. امن ترین کار این است که کامپایلر فرض کند که همه اشاره گرها همیشه نام مستعار دارند. در نتیجه، بسیاری از زبان‌های کامپایل‌شده سطح بالا، مانند C و ++C، طوری تکامل یافته‌اند تا مشخصات معنایی پیچیده‌ تری داشته باشند در این مورد که کامپایلر در کجا مجاز است در مرتب‌سازی مجدد کدها برای دستیابی به بالاترین عملکرد ممکن، مفروضات خوش‌بینانه داشته باشد، و در کجا باید برای جلوگیری از خطر معنایی، مفروضات بدبینانه ای را ایجاد کند. تا حد زیادی بزرگترین دسته بندی از عوارض جانبی در یک زبان رویه ای شامل دستور های نوشتن حافظه می باشد، بنابراین قوانین مربوط به ترتیب حافظه جزء غالب در تعریف معنایی ترتیب برنامه هستند. مرتب سازی مجدد فراخوانی‌های توابع بالا، ممکن است به نظر متفاوت باشند، اما این معمولاً به نگرانی‌هایی تبدیل می شود که در مورد اثر حافظه داخلی در تعامل با دستور حافظه است.

مشکلات و عوارض اضافی[ویرایش]

بهینه سازی تحت عنوانas-if[ویرایش]

کامپایلرهای مدرن بعضی وقت ها با استفاده از یک قاعده as-if یک گام جلوتر می‌روند، که در آن هرگونه ترتیب مجدد (حتی در بین عبارت ها) در صورتی که تاثیری بر نتایج معناشناسی برنامه نداشته باشد، مجاز است. بر اساس این قانون، ترتیب دستور ها در کد ترجمه شده می تواند به شدت از ترتیب برنامه مشخص شده متفاوت باشد. اگر کامپایلر مجاز باشد در مورد دستور های اشاره گر متمایز با عدم همپوشانی مستعار در موردی که چنین نام مستعاری وجود داشته باشد، مفروضات خوش بینانه داشته باشد (این امر معمولاً به عنوان یک برنامه نامناسب طبقه بندی می شود که رفتار نامشخصی از خود نشان می دهد)، نتایج نامطلوب یک تبدیل کد - بهینه‌سازی تهاجمی قبل از اجرای کد یا بازرسی مستقیم کد غیر ممکن است . قلمرو رفتار تعریف‌نشده , تقریبا ً جلوه‌های نامحدود دارد . این مسئولیت برنامه نویس است که مشخصات زبان را به گونه ای در نظر بگیرد تا از نوشتن برنامه هایی که در آن معنا در نتیجه ی هر گونه بهینه سازی کامپایلر تغییر می کند، جلوگیری کند. Fortran به طور سنتی بار زیادی را بر دوش برنامه نویسان قرار می دهد تا از این مسائل آگاه باشد چرا که زبان های برنامه نویسی C و C++ چندان از این موارد عقب نیستند. برخی از زبان‌های سطح بالا، ساختارهای اشاره گر را به طور کلی حذف می‌کنند چرا که این سطح هوشیاری و توجه به جزئیات بسیار بالاست و حتی در بین برنامه‌نویسان حرفه‌ای نمی‌توان آن را حفظ کرد. درک کامل از معناشناسی ترتیب حافظه به عنوان یک تخصص در میان گروهی از برنامه نویس های حرفه ای که در این زمینه بهترین هستند، در نظر گرفته می شود. اکثر برنامه نویسان به درک کافی از این مسائل در حوزه معمولی تخصص خود رضایت می دهند. در نهایت برنامه نویسانی هستند که چارچوب های نرم افزاری را برای پشتیبانی از مدل های محاسباتی همزمان ایجاد می کنند.

نام مستعار متغیرهای محلی[ویرایش]

توجه داشته باشید که متغیرهای محلی را نمی ‌توان بدون نام مستعار فرض کرد، اگر یک اشاره‌گر به چنین متغیری در اشاره کند :

;sum = f(&a) + g(a)

ما نمی دانیم که تابع f با اشاره گر داده شده به a چه کرد. در ساده ترین حالت، f مقدار جدیدی برای متغیر a می نویسد و عبارت به ترتیب اجرا تعریف نشده است. f می تواند چنین رفتاری را با اعمال واجد شرایط ثابت در اعلان آرگومان اشاره گر پنهان کند و عبارت به درستی تعریف شود. بنابراین، فرهنگ C/C++ مدرن تا حدودی در مورد دادن اعلان‌های آرگومان تابع واجد شرایط ثابت در همه موارد قابل اجرا، وسواس زیادی پیدا کرده است. زبان های C و ++C به اجزای داخلی تابع f این اجازه را می‌دهند تا صفت سازگاری را به عنوان یک مصلحت خطرناک نشان دهد. اگر تابع f این کار را به گونه ای انجام دهد که بتواند عبارت بالا را از هم بشکند، در مرحله اول نباید نوع آرگومان اشاره گر را به عنوان ثابت اعلام کند. سایر زبان‌های سطح بالا به یک تضمین قوی بدون هیچ حفره حلقه ای برای نقض متمایل می‌شوند. اگر برنامه شما کتابخانه ای را که به زبان برنامه نویسی دیگری نوشته شده است پیوند دهد، همه شرط ها روی این زبان تضمین نمی شود (اگرچه این طراحی به شدت بد در نظر گرفته می شود).

اجرای مانع حافظه در زمان کامپایل[ویرایش]

این مانع ها از مرتب سازی مجدد دستورها توسط کامپایلر در طول زمان کامپایل جلوگیری می کنند ولی مانع از مرتب سازی مجدد توسط CPU در طول زمان اجرا نمی شوند.

  • هر یک از این دستورها اسمبلر درون خطی GNU، کامپایلر GCC را از مرتب کردن مجدد دستورهای خواندن و نوشتن در اطراف خود منع می کند: [۱]
;asm volatile("" ::: "memory")
;asm__ __volatile__ ("" ::: "memory")__
  • این تابع C11/C++11 کامپایلر را از مرتب کردن مجدد دستور های خواندن و نوشتن در اطراف خود منع می کند: [۲]
  • ;atomic_signal_fence(memory_order_acq_rel)
()memory_barrier__
()ReadWriteBarrier_

موانع ترکیبی[ویرایش]

در بسیاری از زبان های برنامه نویسی، انواع مختلفی از مانع ها را می توان با دستور های دیگر (مانند بارگذاری، ذخیره، افزایش اتمی، مقایسه اتمی و مبادله) ترکیب کرد، بنابراین به هیچ مانع حافظه اضافه ای نیاز نیست. بسته به معماری پردازنده که هدف است، این ساختارهای زبان به دستورالعمل‌های ویژه، به دستورالعمل‌های متعدد (به عنوان مثال مانع و بار)، یا به دستورالعمل‌های معمولی، بسته به تضمین‌های ترتیب حافظه سخت‌افزاری، ترجمه می‌شوند.

مرتب سازی حافظه در زمان اجرا[ویرایش]

در سیستم های ریزپردازنده متقارن چند پردازشی (SMP).[ویرایش]

چند مدل سازگاری با حافظه برای سیستم SMP وجود دارد:

  • سازگاری متوالی (همه خواندن ها و همه نوشتن ها به ترتیب هستند)
  • سازگاری آرام (برای برخی از انواع مرتب سازی مجدد مجاز است)
    • بارها را می توان پس از بارگذاری، مجدداً مرتب کرد (برای عملکرد بهتر انسجام حافظه پنهان، مقیاس بندی بهتر)
    • بارها را می توان پس از ذخیره سازی دوباره مرتب کرد.
    • ذخایر را می توان بعد از ذخیره سازی دوباره مرتب کرد.
    • پس از بارگیری می توان ذخایر را دوباره مرتب کرد.
  • سازگاری ضعیف (خواندن و نوشتن به طور دلخواه مرتب می شوند، فقط با موانع حافظه صریح محدود می شوند)

در برخی از CPU ها

  • دستور های اتمی را می توان با بارها و ذخیره ها مجدداً مرتب کرد. [۶]
  • ممکن است دستورالعمل نامنسجمی برای خط لوله کش (حافظه نهان) وجود داشته باشد که از اجرای کدهای خودتغییر شونده بدون دستورالعمل‌های خیط و بارگذاری مجدد کش دستورالعمل‌ها جلوگیری می‌کند.
  • بارهای وابسته را می توان دوباره مرتب کرد (این برای آلفا منحصر به فرد است). اگر پردازنده بعد از این مرتب‌سازی مجدد، اشاره‌گر به برخی از داده‌ها واکشی کند، ممکن است خود داده‌ها را واکشی نکند، اما از داده‌های قدیمی که قبلاً کش کرده و هنوز باطل نشده‌اند استفاده کند. اجازه دادن به این آرام سازی، سخت‌افزار کش را ساده‌تر و سریع‌تر می‌کند، اما منجر به نیاز به موانع حافظه برای خوانندگان و نویسنده‌ها می‌شود. [۷] در سخت‌افزار آلفا (مانند سیستم‌های چند پردازنده آلفا 21264 )، ابطال‌های خط کش ارسال شده به دیگر پردازنده‌ها به‌طور پیش‌فرض به صورت تنبل پردازش می‌شوند، مگر اینکه صریحاً درخواست شده باشد که بین بارهای وابسته پردازش شوند. مشخصات معماری آلفا همچنین اجازه می دهد تا اشکال دیگر مرتب سازی مجدد بارهای وابسته، به عنوان مثال با استفاده از داده های گمانه زنی قبل از دانستن اشاره گر واقعی برای حذف ارجاع داده شود.
نوع آلفا ARMv7 MIPS RISC-V PA-RISC POWER SPARC X86 AMD64 IA-64 z/Architecture
WMO TSO RMO PSO TSO
Loads can be reordered after loads Y Y بستگی به پیاده سازی دارد Y Y Y Y Y
Loads can be reordered after stores Y Y Y Y Y Y Y
Stores can be reordered after stores Y Y Y Y Y Y Y Y
Stores can be reordered after loads Y Y Y Y Y Y Y Y Y Y Y Y Y
Atomic can be reordered with loads Y Y Y Y Y Y
Atomic can be reordered with stores Y Y Y Y Y Y Y
Dependent loads can be reordered Y
Incoherent instruction cache/pipeline Y Y Y Y Y Y Y Y Y Y
مدل های ترتیب حافظه RISC-V
WMO
ترتیب حافظه ضعیف (پیش‌فرض)
TSO
کل ترتیب ذخیره شده (فقط با افزونه Ztso پشتیبانی می شود)
حالت های ترتیب حافظه SPARC
TSO
کل ترتیب ذخیره شده (پیش‌فرض)
RMO
ترتیب حافظه آرام (در CPU های اخیر پشتیبانی نمی شود)
PSO
ترتیب ذخیره شده جزئی (در CPU های اخیر پشتیبانی نمی شود)

پیاده سازی مانع حافظه سخت افزاری[ویرایش]

بسیاری از معماری‌ها با پشتیبانی SMP دارای دستورهای سخت‌افزاری خاصی هستند که برای خواندن و نوشتن در طول زمان اجرا هستند.

lence (asm), void _mm_lfence (void)
sfence (asm), void _mm_sfence (void)
mfence (asm), void _mm_mfence (void)
همگام سازی (asm)
همگام سازی (asm)
mf (asm)
dcs (asm)
dmb (asm)
dsb (asm)
isb (asm)

پشتیبانی کامپایلر برای موانع حافظه سخت افزاری[ویرایش]

برخی از کامپایلرها از تابع ذاتی پشتیبانی می‌کنند که دستورهای مانع حافظه که از نوع سخت افزاری هستند را خارج می‌کنند:

  • GCC ، [۹] نسخه 4.4.0 و جدیدتر، [۱۰] دارای __sync_synchronize است.
  • از C11 و C++11 یک دستور atomic_thread_fence() اضافه شد.
  • کامپایلر Microsoft Visual C++ [۱۱] دارای MemoryBarrier() است.
  • Sun Studio Compiler Suite [۱۲] دارای __machine_r_barrier ، __machine_w_barrier و __machine_rw_barrier است.

همچنین ببینید[ویرایش]

منابع[ویرایش]

  1. GCC compiler-gcc.h بایگانی‌شده در ۲۰۱۱-۰۷-۲۴ توسط Wayback Machine
  2. "std::atomic_signal_fence". ccpreference.
  3. ECC compiler-intel.h بایگانی‌شده در ۲۰۱۱-۰۷-۲۴ توسط Wayback Machine
  4. Intel(R) C++ Compiler Intrinsics Reference

    Creates a barrier across which the compiler will not schedule any data access instruction. The compiler may allocate local data in registers across a memory barrier, but not global data.

  5. Visual C++ Language Reference _ReadWriteBarrier
  6. Victor Alessandrini, 2015. Shared Memory Application Programming: Concepts and Strategies in Multicore Application Programming. Elsevier Science. p. 176. شابک ‎۹۷۸−۰−۱۲−۸۰۳۸۲۰−۸.
  7. Reordering on an Alpha processor by Kourosh Gharachorloo
  8. Data Memory Barrier, Data Synchronization Barrier, and Instruction Synchronization Barrier.
  9. Atomic Builtins
  10. "36793 – x86-64 does not get __sync_synchronize right".
  11. MemoryBarrier macro
  12. Handling Memory Ordering in Multithreaded Applications with Oracle Solaris Studio 12 Update 2: Part 2, Memory Barriers and Memory Fence

مطالعه بیشتر[ویرایش]

[[رده:همروندی]] [[رده:طراحی زبان‌های برنامه‌نویسی]] [[رده:کامپایلرسازی]] [[رده:مدل‌های استحکام]] [[رده:حافظه رایانه]] [[رده:معماری رایانه]] [[رده:اصول سیستم های کامپیوتری]]