সি 11 পারমাণবিক অর্জন / প্রকাশ এবং x86_64 লোড / স্টোরের মিলনের অভাব?


10

আমি সি 11 স্ট্যান্ডার্ডের 5.1.2.4 বিভাগের সাথে বিশেষত মুক্তি / অর্জনের শব্দার্থবিজ্ঞানের সাথে লড়াই করছি। আমি নোট করেছি যে https://preshing.com/20120913/acquire-and-release-semantics/ (অন্যদের মধ্যে) বলেছেন যে:

... রিলিজ শব্দার্থবিজ্ঞান প্রোগ্রাম ক্রমে এর আগে যে কোনও পড়া বা লেখার ক্রিয়াকলাপের সাথে রাইটিং-রিলিজের মেমরি পুনঃক্রম করতে বাধা দেয়।

সুতরাং, নিম্নলিখিতগুলির জন্য:

typedef struct test_struct
{
  _Atomic(bool) ready ;
  int  v1 ;
  int  v2 ;
} test_struct_t ;

extern void
test_init(test_struct_t* ts, int v1, int v2)
{
  ts->v1 = v1 ;
  ts->v2 = v2 ;
  atomic_store_explicit(&ts->ready, false, memory_order_release) ;
}

extern int
test_thread_1(test_struct_t* ts, int v2)
{
  int v1 ;
  while (atomic_load_explicit(&ts->ready, memory_order_acquire)) ;
  ts->v2 = v2 ;       // expect read to happen before store/release 
  v1     = ts->v1 ;   // expect write to happen before store/release 
  atomic_store_explicit(&ts->ready, true, memory_order_release) ;
  return v1 ;
}

extern int
test_thread_2(test_struct_t* ts, int v1)
{
  int v2 ;
  while (!atomic_load_explicit(&ts->ready, memory_order_acquire)) ;
  ts->v1 = v1 ;
  v2     = ts->v2 ;   // expect write to happen after store/release in thread "1"
  atomic_store_explicit(&ts->ready, false, memory_order_release) ;
  return v2 ;
}

যেখানে এগুলি কার্যকর করা হয়:

>   in the "main" thread:  test_struct_t ts ;
>                          test_init(&ts, 1, 2) ;
>                          start thread "2" which does: r2 = test_thread_2(&ts, 3) ;
>                          start thread "1" which does: r1 = test_thread_1(&ts, 4) ;

সুতরাং, আমি থ্রেড "1" এর কাছে r1 == 1 এবং থ্রেড "2" এর কাছে r2 = 4 থাকব expect

আমি এটি আশা করব কারণ (5.1.2.4 বিভাগের 16 এবং 18 অনুচ্ছেদের পরে):

  • সমস্ত (পারমাণবিক নয়) পড়া এবং লেখাগুলি "পূর্বে ধারাবাহিক" এবং সুতরাং "1" থ্রেডে পরমাণু রচনা / প্রকাশের আগে "ঘটে যায়",
  • যা "আন্ত-থ্রেড-ঘটে" এর আগে "2" থ্রেডে পারমাণবিক পাঠ / অর্জন করে (যখন এটি 'সত্য' পড়ে),
  • যা পরবর্তীতে "পূর্বে ক্রমযুক্ত" এবং সুতরাং (পরমাণু নয়) পড়া এবং লেখার (থ্রেড "2") এর আগে "ঘটে যায়"।

তবে এটি পুরোপুরি সম্ভব যে আমি মান বুঝতে ব্যর্থ হয়েছি।

আমি পর্যবেক্ষণ করেছি যে x86_64 এর জন্য উত্পন্ন কোডটিতে অন্তর্ভুক্ত রয়েছে:

test_thread_1:
  movzbl (%rdi),%eax      -- atomic_load_explicit(&ts->ready, memory_order_acquire)
  test   $0x1,%al
  jne    <test_thread_1>  -- while is true
  mov    %esi,0x8(%rdi)   -- (W1) ts->v2 = v2
  mov    0x4(%rdi),%eax   -- (R1) v1     = ts->v1
  movb   $0x1,(%rdi)      -- (X1) atomic_store_explicit(&ts->ready, true, memory_order_release)
  retq   

test_thread_2:
  movzbl (%rdi),%eax      -- atomic_load_explicit(&ts->ready, memory_order_acquire)
  test   $0x1,%al
  je     <test_thread_2>  -- while is false
  mov    %esi,0x4(%rdi)   -- (W2) ts->v1 = v1
  mov    0x8(%rdi),%eax   -- (R2) v2     = ts->v2   
  movb   $0x0,(%rdi)      -- (X2) atomic_store_explicit(&ts->ready, false, memory_order_release)
  retq   

এবং সরবরাহ করা হয়েছে যে আর 1 এবং এক্স 1 ক্রমে ঘটে, এটি আমার প্রত্যাশার ফলাফল দেয়।

তবে x86_64 সম্পর্কে আমার বোধগম্যতা হ'ল পাঠগুলি অন্য পাঠকের সাথে ক্রম ঘটে এবং লেখাগুলি অন্য লেখকের সাথে ক্রম ঘটে, তবে পড়া এবং লেখাগুলি একে অপরের সাথে ক্রমে না ঘটে। যা বোঝায় যে এক্স 1 এর পক্ষে আর 1 এর আগে হওয়া সম্ভব, এবং এমনকি এক্স 1, এক্স 2, ডাব্লু 2, আর 1 এর ক্রমটি ঘটে - আমি বিশ্বাস করি। [এটি মারাত্মকভাবে অসম্ভব বলে মনে হচ্ছে, তবে আর 1 যদি কিছু ক্যাশে ইস্যু করে থাকে তবে?]

দয়া করে: আমি কি বুঝতে পারছি না?

আমি লক্ষ করুন যে, যদি আমি লোড / দোকান পরিবর্তন ts->readyকরতে memory_order_seq_cst, দোকানে জন্য উত্পন্ন কোড হল:

  xchg   %cl,(%rdi)

যা আমার x86_64 বোঝার সাথে সামঞ্জস্যপূর্ণ এবং আমি প্রত্যাশিত ফলাফল দেব।


5
X86-এ, সমস্ত সাধারণ (অস্থায়ী নয়) স্টোরগুলিতে প্রকাশিত শব্দার্থক শব্দ রয়েছে। Intel 64 এবং IA-32 আর্কিটেকচারের সফটওয়্যার উন্নয়নকারীর ম্যানুয়াল ভলিউম 3 (3A, 3B, 3C & 3D): সিস্টেম নির্দেশিকা প্রোগ্রামিং , 8.2.3.3 Stores Are Not Reordered With Earlier Loads। সুতরাং আপনার সংকলক আপনার কোডটি সঠিকভাবে অনুবাদ করছে (কত আশ্চর্যজনক) যেমন আপনার কোডটি কার্যকরভাবে পুরোপুরি অনুক্রমিক এবং একই সাথে আকর্ষণীয় কিছুই ঘটে না।
ইওএফ

ধন্যবাদ ! (আমি চুপচাপ bonণগ্রহী হয়ে যাচ্ছিলাম।) এফডাব্লুআইডাব্লু আমি লিঙ্কটি সুপারিশ করি - বিশেষত ধারা 3, "প্রোগ্রামারের মডেল"। তবে যে ভুলটি আমি পড়েছিলাম তা এড়াতে, দ্রষ্টব্য যে "৩.১ দ্য অ্যাবস্ট্রাক্ট মেশিন" এ "হার্ডওয়্যার থ্রেড" রয়েছে যার প্রত্যেকটিতে " নির্দেশ কার্যকরকরণের একক ইন-অর্ডার প্রবাহ" (আমার জোর যুক্ত করা হয়েছে)। আমি এখন সি 11 স্ট্যান্ডার্ড ... কম জ্ঞানীয় অসচ্ছলতা সহ বুঝতে চেষ্টা করতে ফিরে যেতে পারি :-)
ক্রিস হল

উত্তর:


1

x86 এর মেমরি মডেলটি মূলত ক্রম-ধারাবাহিকতা এবং একটি স্টোর বাফার (স্টোর ফরোয়ার্ডিং সহ)। তাই প্রত্যেক দোকান মুক্তি-স্টোর হয় 1 । এ কারণেই কেবল সিক-সিএসটি স্টোরগুলিতে কোনও বিশেষ নির্দেশাবলীর প্রয়োজন। ( সি / সি ++ 11 এটমিক্সকে ম্যাসেপিংয়ের asm )। এছাড়াও, https://stackoverflow.com/tags/x86/info এর x86 ডক্সের কিছু লিঙ্ক রয়েছে, যার মধ্যে x86-TSO মেমরি মডেলের আনুষ্ঠানিক বিবরণ রয়েছে (বেশিরভাগ মানুষের পক্ষে মূলত অপঠনযোগ্য; অনেক সংজ্ঞা দিয়েই ওয়াডিং প্রয়োজন)।

যেহেতু আপনি ইতিমধ্যে জেফ প্রেসিংয়ের দুর্দান্ত সিরিজ নিবন্ধগুলি পড়ছেন, তাই আমি আপনাকে আরও একটি বিবরণে নির্দেশ করব যা আরও বিস্তারিতভাবে বিবেচিত হয়: https://preshing.com/20120930/weak-vs- স্ট্র-memory-models/

X86 এ কেবলমাত্র পুনঃনির্ধারণের অনুমতি দেওয়া হ'ল স্টোরলড, লোডস্টোর নয় , যদি আমরা সেই পদগুলিতে কথা বলি। (স্টোর ফরোয়ার্ডিং অতিরিক্ত মজাদার জিনিসগুলি করতে পারে যদি কোনও লোড আংশিকভাবে কোনও স্টোরকে ওভারল্যাপ করে; বিশ্বব্যাপী অদৃশ্য লোড নির্দেশিকা , যদিও আপনি এটি কখনই সংকলক-উত্পন্ন কোডে পাবেন না stdatomic))

@ ইওফ ইন্টেলের ম্যানুয়াল থেকে সঠিক উদ্ধৃতি দিয়ে মন্তব্য করেছে:

ইন্টেল ®৪ এবং আইএ -32 আর্কিটেকচার সফটওয়্যার বিকাশকারীর ম্যানুয়াল ভলিউম 3 (3 এ, 3 বি, 3 সি এবং 3 ডি): সিস্টেম প্রোগ্রামিং গাইড, 8.2.3.3 স্টোর পূর্বের লোডগুলির সাথে পুনরায় সাজানো যায় না।


পাদটীকা 1: দুর্বলভাবে অর্ডার করা এনটি স্টোরগুলি উপেক্ষা করে; এই কারণেই আপনি সাধারণত sfenceএনটি স্টোরগুলি করার পরে। C11 / C ++ 11 বাস্তবায়ন ধরে নেওয়া হয় আপনি এনটি স্টোর ব্যবহার করছেন না। আপনি যদি _mm_sfenceহন তবে এটি আপনার এনটি স্টোরকে সম্মান করে তা নিশ্চিত করার জন্য একটি রিলিজ অপারেশনের আগে ব্যবহার করুন । (সাধারণভাবে / অন্যান্য ক্ষেত্রে ব্যবহার করবেন না_mm_mfence_mm_sfence ; সাধারণত আপনাকে কেবল কমপাইল-টাইম পুনর্নির্মাণকে ব্লক করতে হবে Or বা অবশ্যই কেবল স্টেট্যাটমিক ব্যবহার করুন))


আমি x86-TSO পেয়েছি : x86 মাল্টিপ্রসেসরগুলির জন্য একটি কঠোর এবং ব্যবহারযোগ্য প্রোগ্রামার মডেল যা আপনি উল্লেখ করেছেন (সম্পর্কিত) ফর্মাল বিবরণের চেয়ে বেশি পাঠযোগ্য । তবে আমার আসল উচ্চাকাঙ্ক্ষা হ'ল সি 11 / সি 18 স্ট্যান্ডার্ডের 5.1.2.4 এবং 7.17.3 বিভাগগুলি সম্পূর্ণরূপে বোঝা। বিশেষত, আমি মনে করি আমি মুক্তি / অর্জন / অর্জন + রিলিজ পেয়েছি তবে মেমরি_অর্ডার_সেক_সিএসটি আলাদাভাবে সংজ্ঞায়িত হয়েছে এবং তারা কীভাবে একসাথে ফিট হয় তা দেখার জন্য আমি লড়াই করছি :-(
ক্রিস হল

@ ক্রিসহল: আমি বুঝতে পেরেছি যে ঠিক কীভাবে দুর্বল ac / / rel হতে পারে ঠিক তা বুঝতে পেরেছি এবং এর জন্য আপনাকে পাওয়ারের মতো মেশিনের দিকে নজর দেওয়া দরকার যা IRW পুনর্নির্মাণ করতে পারে। (যা সিক-সিএসটি নিষিদ্ধ করে তবে অ্যাকি / রিল না দেয়) বিভিন্ন থ্রেডে দুটি স্থানে দুটি পরমাণু লেখার ক্ষেত্রে কি অন্য থ্রেডের দ্বারা সর্বদা একই ক্রমে দেখা যাবে? । এছাড়াও সি ++ 11 এ স্টোরলড বাধা কীভাবে অর্জন করবেন? সিঙ্ক্রোনাইজ-সহ বা সবকিছু-সিক-সিএসটি ক্ষেত্রে বাইরের অর্ডার দেওয়ার বিষয়ে স্ট্যান্ডার্ড আনুষ্ঠানিকভাবে কতটা গ্যারান্টি দেয় সে সম্পর্কে কিছুটা আলোচনা রয়েছে।
পিটার কর্ডেস

@ ক্রিসহল: সিক-সিএসটি মূল জিনিস হ'ল স্টোরলয়েড পুনঃক্রম block (X86-এ এটি একা / রিলকের বাইরে একমাত্র জিনিস)। preshing.com/20120515/mmory-reordering-caught-in-tact- এএসএম ব্যবহার করে তবে এটি সিক-সিএসটি বনাম acq / rel এর সমতুল্য
পিটার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.