আইবিএম উদাহরণ কোড, পুনরায় প্রবেশকারী ফাংশনগুলি আমার সিস্টেমে কাজ করে না


11

আমি প্রোগ্রামিংয়ে পুনরায় প্রবেশের পড়াশোনা করছিলাম। আইবিএমের এই সাইটে (সত্যই ভাল)। আমি নীচে অনুলিপি করে একটি কোড প্রতিষ্ঠিত করেছি। এটি প্রথম কোড যা ওয়েবসাইটটি রোল করে চলেছে।

কোডটি একটি "বিপজ্জনক প্রসঙ্গে" ক্রমাগত পরিবর্তিত হয় এমন দুটি মান মুদ্রণের মাধ্যমে একটি পাঠ্য প্রোগ্রামের অ-লিনিয়ার বিকাশের (অ্যাসিনক্রোনিকটি) পরিবর্তনশীলের ভাগ করে নেওয়া অ্যাক্সেস জড়িত বিষয়গুলি দেখানোর চেষ্টা করে।

#include <signal.h>
#include <stdio.h>

struct two_int { int a, b; } data;

void signal_handler(int signum){
   printf ("%d, %d\n", data.a, data.b);
   alarm (1);
}

int main (void){
   static struct two_int zeros = { 0, 0 }, ones = { 1, 1 };

   signal (SIGALRM, signal_handler); 
   data = zeros;
   alarm (1);
   while (1){
       data = zeros;
       data = ones;
   }
}

আমি কোড চালানোর চেষ্টা করার সময় সমস্যাগুলি উপস্থিত হয়েছিল (বা আরও ভাল, প্রদর্শিত হয়নি)। আমি ডিজিটাল কনফিগারেশনে জিসিসি সংস্করণ 6.3.0 20170516 (ডেবিয়ান 6.3.0-18 + deb9u1) ব্যবহার করছিলাম। বিপথগামী আউটপুট ঘটে না। "ভুল" জোড়ার মান পাওয়ার ফ্রিকোয়েন্সি 0!

কি হচ্ছে সব পরে? স্ট্যাটিক গ্লোবাল ভেরিয়েবলগুলি ব্যবহার করে পুনরায় প্রবেশের ক্ষেত্রে কেন কোনও সমস্যা নেই?


1
নিশ্চিত করুন যে সমস্ত সংকলক অপ্টিমাইজেশন অক্ষম হয়েছে এবং আবার চেষ্টা করুন
রোয়াইমা

আমার ধারণা ছিল ... তবে আমি কোন বিকল্পগুলি পরিবর্তন করব? আমার কোন ধারণা নাই. :-(
ড্যানিয়েল বানদীরা

5
এটি দেখতে একটি প্রোগ্রামিং প্রশ্নের মতো (স্ট্যাক ওভারফ্লো)। এটি ডোজ এখানে ভাল স্থাপন করা হয় বলে মনে হচ্ছে না। (দুঃখিত, আমি এখানে সাব-সাইটগুলি কম ছিলাম; এটি এতটাই কেটে গেছে that তবে এটি
সেভাবেই হয় c

1
সর্বাধিক সহজ পুনঃপ্রবিষ্ট কোডটি পরিবর্তনযোগ্য ut
ctrl-alt-delor 18

প্রথম মুহুর্তে, আমি মনে করি যে প্রশ্নটি জিসিসি এবং লিনাক্স পরিবেশের সাথে সম্পর্কিত। উদাহরণস্বরূপ, বিবর্তনকারী ওএসের সময়সূচী (হ্যান্ডলারের রুটিনটি কল করার আগে বাধা সংকেতের পরে আরও প্রোগ্রামের পাঠ্য কার্যকর করে), উদাহরণস্বরূপ।
ড্যানিয়েল বানদীরা

উত্তর:


12

এটি আসলে পুনরায় প্রবেশ নয় ; আপনি একই থ্রেডে (বা বিভিন্ন থ্রেডে) দুবার কোনও ফাংশন পরিচালনা করছেন না । আপনি এটি পুনরাবৃত্তির মাধ্যমে বা অন্য ফাংশনে কলব্যাক ফাংশন-পয়েন্টার আর্গ হিসাবে বর্তমান ফাংশনের ঠিকানাটি পাস করার মাধ্যমে পেতে পারেন। (এবং এটি অনিরাপদ হবে না কারণ এটি সিনক্রোনাস হবে)।

এটি একটি সিগন্যাল হ্যান্ডলার এবং মূল থ্রেডের মধ্যে কেবল প্লেইন ভ্যানিলা ডেটা রেস ইউবি (অপরিজ্ঞাত আচরণ): কেবল এটির জন্যই sig_atomic_tসুরক্ষিত গ্যারান্টিযুক্ত । অন্যরা কাজের ক্ষেত্রে ঘটতে পারে, যেমন আপনার ক্ষেত্রে যেখানে 8-বাইট অবজেক্টটি x86-64 এ একটি নির্দেশ দিয়ে লোড বা সঞ্চয় করা যায় এবং সংকলকটি সেই asm বাছাই করার জন্য ঘটে। (@ আইক্রাসের উত্তরগুলি দেখায়)।

এমসিইউ প্রোগ্রামিং দেখুন - লুপের সময় সি ++ ও 2 অপটিমাইজেশন বিরতি - একটি একক কোর মাইক্রোকন্ট্রোলারের একটি বিঘ্নিত হ্যান্ডলার মূলত সিঙ্গল থ্রেডেড প্রোগ্রামে সিগন্যাল হ্যান্ডলার হিসাবে একই জিনিস। সেক্ষেত্রে ইউবির ফলাফল হ'ল একটি লুপ থেকে লোড উত্তোলন হয়।

আপনার ডেটা-রেস ইউবির কারণে টিয়ার কেসটি কেস কেস সম্ভবত 32-বিট মোডে বিকাশ / পরীক্ষা করা হয়েছিল, বা কোনও পুরানো ডम्बर সংকলক সহ স্ট্রাক্ট সদস্যদের আলাদাভাবে লোড করেছে।

আপনার ক্ষেত্রে, সংকলকটি অসীম লুপ থেকে দোকানগুলি অনুকূল করে তুলতে পারে কারণ কোনও ইউবি-মুক্ত প্রোগ্রাম সেগুলি পর্যবেক্ষণ করতে পারে নি। dataহয় _Atomicবা নাvolatile , এবং লুপে অন্য কোনও পার্শ্ব প্রতিক্রিয়া নেই। সুতরাং কোনও পাঠকই এই লেখকের সাথে সিঙ্ক্রোনাইজ হওয়ার উপায় নেই। বাস্তবে এটি ঘটে যদি আপনি অনুকূলিতকরণ সক্ষম করে ( গডবোল্ট মূলের নীচে একটি ফাঁকা লুপ দেখায়) দিয়ে সংকলন করেন । আমি স্ট্রাক্টটি দুটি করেও পরিবর্তন করেছি long longএবং লিসিপি এর movdqaআগে জিসিসি একক 16-বাইট স্টোর ব্যবহার করে। (এটি গ্যারান্টিযুক্ত পারমাণবিক নয়, তবে এটি প্রায় সমস্ত সিপিইউতে অনুশীলন করা হয়েছে, ধরে নেওয়া হয়েছে যে এটি প্রান্তিককরণ করা হয়েছে, বা ইন্টেল কেবল একটি ক্যাশে-লাইন সীমানাটি অতিক্রম করে না। x86-তে প্রাকৃতিকভাবে সংযুক্ত ভেরিয়েবল অণুতে কেন পূর্ণসংখ্যক নিয়োগ রয়েছে? )

সুতরাং অপ্টিমাইজেশান সক্ষম করার সাথে সংকলন করাও আপনার পরীক্ষাকে ভঙ্গ করবে এবং প্রতিবার আপনাকে একই মান দেখায় show সি কোনও বহনযোগ্য সমাবেশের ভাষা নয়।

volatile struct two_intসংকলককে এগুলি অপ্টিমাইটিস না করতে বাধ্য করবে, তবে এটি পুরো স্ট্রাকটকে পরমাণুগতভাবে লোড / সঞ্চয় করতে বাধ্য করবে না । (এটা চাই থামাতে পারেন এমনটি থেকে এটা, যদিও।) লক্ষ্য করুন volatileনেই না ডেটা-জাতি UB এড়াতে, কিন্তু বাস্তবে এটা আন্ত থ্রেড যোগাযোগের জন্য যথেষ্ট এবং কিভাবে মানুষ (ইনলাইন এ এস এম সহ) হাতে ঘূর্ণিত atomics নির্মিত ছিল সাধারণ সিপিইউ আর্কিটেকচারের জন্য সি 11 / সি ++ 11 এর আগে। তারা ক্যাশে-সুসঙ্গত তাই volatileহয় অনুশীলন বেশিরভাগই অনুরূপ _Atomicসঙ্গেmemory_order_relaxed বিশুদ্ধ-লোড এবং বিশুদ্ধ-স্টোর, যদি ধরনের জন্য ব্যবহার যথেষ্ট যে কম্পাইলার একটি একক নির্দেশ ব্যবহার করবে যাতে আপনি বিচ্ছিন্নকরণ পাবেন না সংকীর্ণ। এবং অবশ্যইvolatileআইএসও সি স্ট্যান্ডার্ড বনাম লিখিত কোডের কোনও গ্যারান্টি নেই যা একই asm ব্যবহার করে _Atomicএবং মো_রেল্যাক্সযুক্ত comp


আপনি একটি ফাংশন করেছিলাম ছিল global_var++;একটি অন intবা long longআপনি মূল থেকে চালানো এবং একটি সংকেত হ্যান্ডলার থেকে অ্যাসিঙ্ক্রোনাস, যে ডেটা-জাতি UB তৈরি করতে ব্যবহার পুনরায় entrancy একটি উপায় হতে হবে।

এটি কীভাবে সংকলিত হয়েছে তার উপর নির্ভর করে (কোনও স্মৃতি গন্তব্য ইনক বা যোগ করতে বা লোড / ইনক / স্টোরকে আলাদা করতে) এটি পরমাণু হবে বা একই থ্রেডে সংকেত হ্যান্ডলারের ক্ষেত্রে নয়। 'Int num' এর জন্য num ++ পারমাণবিক হতে পারে দেখুন ? x86 এবং সি ++ এ পারমাণবিকতা সম্পর্কে আরও জানতে। ( সি 11 এর stdatomic.hএবং _Atomicবৈশিষ্ট্যটি সি ++ 11 এর std::atomic<T>টেম্পলেটের সমতুল্য কার্যকারিতা সরবরাহ করে )

কোনও নির্দেশের মাঝে বাধা বা অন্যান্য ব্যতিক্রম ঘটতে পারে না, সুতরাং একটি স্মৃতি-গন্তব্য যুক্ত হ'ল পারমাণবিক কব্জি। প্রসঙ্গটি একটি একক-কোর সিপিউতে স্যুইচ করে। কেবলমাত্র একটি (ক্যাশে সুসংহত) ডিএমএ লেখক সিঙ্গল কোর সিপিইউতে প্রিফিক্স add [mem], 1ছাড়াই একটি থেকে ইনক্রিমেন্টটি "পদক্ষেপ" করতে পারে lock। অন্য কোনও থ্রোর নেই যা অন্য থ্রেড চলতে পারে।

সুতরাং এটি সংকেতের ক্ষেত্রে অনুরূপ: একটি সংকেত হ্যান্ডলারটি সূচিত হ্যান্ডলিং করে থ্রেডের সাধারণ সম্পাদনের পরিবর্তে চলতে থাকে , সুতরাং এটি একটি নির্দেশের মাঝখানে পরিচালনা করা যায় না।


2
Icaru এর উত্তর আমার পক্ষে যথেষ্ট সত্ত্বেও আমি আপনাকে সেরা উত্তর হিসাবে গ্রহণ করতে বাধ্য হয়েছিলাম। আপনি যে স্পষ্ট ধারণাটি আমাদের বলেছিলেন সেগুলি আমাকে এই দিন (এবং আরও) অধ্যয়নের জন্য এক বালতি বিষয়বস্তু দিন। আসলে, আপনি প্রথম নজরে প্রথম দুটি অনুচ্ছেদে যা লিখেছেন তা খুব কমই পেয়েছি। ধন্যবাদ! আপনি যদি কম্পিউটার এবং প্রোগ্রামিং সম্পর্কে ইন্টারনেটে পাবলিক নিবন্ধগুলি করেন তবে আমাদের লিঙ্কটি দিন!
ড্যানিয়েল বন্দেরা

17

এ খুঁজছি godbolt কম্পাইলার এক্সপ্লোরার (অনুপস্থিত মধ্যে যোগ করার পরে #include <unistd.h>), একটি দেখে প্রায় কোনো, x86_64 কম্পাইলার কোড উত্পন্ন ব্যবহারসমূহ QWORD প্যাচসমূহ লোড করতে onesএবং zerosএকটি একক নির্দেশ করে।

        mov     rax, QWORD PTR main::ones[rip]
        mov     QWORD PTR data[rip], rax

আইবিএম সাইটটি বলছে On most machines, it takes several instructions to store a new value in data, and the value is stored one word at a time.যে ২০০৫ সালে সাধারণত সিপাসের ক্ষেত্রে এটি সত্য হতে পারে তবে কোড শোগুলি এখন সত্য নয়। কাঠামোটি দুটি ইন্টের চেয়ে দুটি লম্বা হওয়ার কারণে সমস্যাটি দেখাবে।

আমি আগে লিখেছি যে এটি "পারমাণবিক" যা অলস ছিল। প্রোগ্রামটি কেবল একটি সিপিইউতে চলছে। প্রতিটি নির্দেশ এই সিপিইউর দৃষ্টিকোণ থেকে সম্পূর্ণ হবে (ধরে নিবেন যে ডিএমএর মতো মেমরির কোনও পরিবর্তন নেই)।

সুতরাং Cস্তরে এটি সংজ্ঞায়িত করা হয় না যে সংকলক কাঠামোটি লেখার জন্য একটি একক নির্দেশকে বেছে নেবে এবং তাই আইবিএম কাগজে উল্লিখিত দুর্নীতি হতে পারে। বর্তমান সিপাসকে লক্ষ্য করে আধুনিক সংকলকগণ একক নির্দেশ ব্যবহার করে। একক থ্রেডেড প্রোগ্রামের জন্য দুর্নীতি এড়াতে একক নির্দেশনা যথেষ্ট ভাল।


3
থেকে ডাটা টাইপ পরিবর্তন করার চেষ্টা করুন intথেকে long long, এবং 32bit কম্পাইল। পাঠটি হ'ল আপনি কখনই জানেন না কখন / কখন তা ভেঙে যায়।
ctrl-alt-delor

2
তার মানে, আমার মেশিনে, এই দুটি মান নির্ধারণ করা একটি পারমাণবিক অপারেশন? (x86_64 আর্কিটেকচারের সংকলন বিবেচনা করে)
ড্যানিয়েল বান্দিরা

1
long longx86-64: 16-বাইটের জন্য এখনও একটি নির্দেশকে সংকলন করে movdqa। আপনি যতক্ষণ না আপনার গডবোল্ট লিঙ্কের মতো অপ্টিমাইজেশন অক্ষম করেন। (জিসিসির ডিফল্ট হ'ল -O0ডিবাগ মোড, যা স্টোর / পুনরায় লোডের শব্দে পূর্ণ এবং সাধারণত দেখতে আকর্ষণীয় নয়))
পিটার কর্ডেস

সমস্ত মন্তব্য পড়ার পরে আমি টাইপটি "দীর্ঘ দীর্ঘ" এ পরিবর্তন করেছি। ফলাফলটি আকর্ষণীয় ছিল: প্রতীক্ষিত ফলাফলগুলি অর্জন করা হয়েছিল এবং কিছু কাউন্টার স্থাপন করে এটি অন্য কোডগুলির সাথে কীভাবে মেলে না এমন তথ্যের হারকে প্রভাবিত করে তা অন্যদের ধারণাগুলি উন্নত করতে সক্ষম হয়েছিল। সমস্ত সহায়তার জন্য আপনাকে ধন্যবাদ!
ড্যানিয়েল বানদীরা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.