কাঁটাচামচ () সহ কোনও প্রোগ্রাম কেন কখনও কখনও তার আউটপুট একাধিকবার মুদ্রণ করে?


50

প্রোগ্রাম 1 এ Hello worldএকবার মুদ্রিত হয়ে যায়, তবে আমি যখন \nএটি সরিয়ে দিয়ে চালিত করি (প্রোগ্রাম 2), আউটপুট 8 বার মুদ্রিত হয়। কেউ দয়া করে আমাকে এখানে তাত্পর্যটি ব্যাখ্যা করতে পারেন \nএবং এটি কীভাবে প্রভাবিত করে fork()?

প্রোগ্রাম 1

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    printf("hello world...\n");
    fork();
    fork();
    fork();
}

আউটপুট 1:

hello world... 

প্রোগ্রাম 2

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    printf("hello world...");
    fork();
    fork();
    fork();
}

আউটপুট 2:

hello world... hello world...hello world...hello world...hello world...hello world...hello world...hello world...

10
কোনও ফাইল ( ./prog1 > prog1.out) বা পাইপ ( ./prog1 | cat) এ আউটপুট সহ প্রোগ্রাম 1 চালানোর চেষ্টা করুন । আপনার মনকে ফুটিয়ে তুলতে প্রস্তুত করুন। :-) ⁠
জি-ম্যান

প্রাসঙ্গিক প্রশ্ন + এ এই সমস্যার অন্য রূপটি coveringেকে দেয়: সি সিস্টেম ("বাশ") স্টিডিনকে উপেক্ষা করে
মাইকেল হোমার

13
এটি কিছু ঘনিষ্ঠ ভোট সংগ্রহ করেছে, সুতরাং এ সম্পর্কে একটি মন্তব্য: "ইউএনআইএক্স সি এপিআই এবং সিস্টেম ইন্টারফেস" এ প্রশ্নগুলি স্পষ্টভাবে অনুমোদিত । বাফারিংয়ের সমস্যাগুলি শেল স্ক্রিপ্টগুলিতেও একটি সাধারণ মুখোমুখি এবং fork()কিছুটা ইউনিক্স-নির্দিষ্টও রয়েছে, তাই দেখে মনে হবে এটি ইউনিক্স.এসই-এর জন্য বেশ অনন্য বিষয় is
ilkkachu

@ ইল্কাচ্চু আসলে, আপনি যদি এই লিঙ্কটি পড়ে থাকেন এবং মেটা প্রশ্নটি এটি উল্লেখ করেন তবে এটি খুব স্পষ্টভাবে বানান করে দিয়েছে যে এটি বিষয়বস্তু। যেহেতু কিছু কিছু সি, এবং ইউনিক্সে সি থাকে, কারণ এটি বিষয়টিকে তৈরি করে না।
প্যাট্রিক

@ পেট্রিক, আসলে, আমি করেছি। এবং আমি এখনও মনে করি এটি "কারণের মধ্যে" ধারাটিতে ফিট করে তবে অবশ্যই এটি আমার জন্য just
ইলক্কাচু

উত্তর:


93

সি লাইব্রেরির printf()ফাংশনটি ব্যবহার করে স্ট্যান্ডার্ড আউটপুট এ আউটপুট দেওয়ার সময় আউটপুটটি সাধারণত বাফার হয়। আপনি কোনও নতুন লাইন আউটপুট না দেওয়া, কল করা fflush(stdout)বা প্রোগ্রামটি প্রস্থান করার আগ পর্যন্ত বাফারটি ফ্লাশ করা হয় না ( _exit()যদিও কল করার মাধ্যমে নয় )। স্ট্যান্ডার্ড আউটপুট স্ট্রিমটি কোনও টিটিওয়াইয়ের সাথে সংযুক্ত হলে এইভাবে ডিফল্ট লাইন-বাফার হয়।

আপনি যখন "প্রোগ্রাম 2" এ প্রক্রিয়াটি কাঁটাচাল করেন, তখন শিশু প্রক্রিয়াবিহীন আউটপুট বাফার সহ পিতামাতার প্রক্রিয়ার প্রতিটি অংশকে উত্তরাধিকার সূত্রে পায়। এটি কার্যকরভাবে প্রতিটি শিশু প্রক্রিয়াতে আনলকৃত বাফারটিকে অনুলিপি করে।

প্রক্রিয়াটি শেষ হয়ে গেলে, বাফারগুলি ফ্লাশ করা হয়। আপনি মোট আটটি প্রক্রিয়া (মূল প্রক্রিয়া সহ) শুরু করেন এবং প্রতিটি স্বতন্ত্র প্রক্রিয়া সমাপ্ত হওয়ার পরে ফলস্বরূপ বাফারটি ফ্লাশ করা হবে।

এটি আটটি কারণ প্রতিটিতেই fork()আপনি আপনার আগে যে পরিমাণ প্রক্রিয়া করেছিলেন তার দ্বিগুণ হয়েছিলেন fork()(যেহেতু তারা নিঃশর্ত) এবং আপনার এর মধ্যে তিনটি রয়েছে (২ 3 = 8)।


14
সম্পর্কিত: আপনি শেষ করতে পারেন mainসঙ্গে _exit(0)শুধু অনিদ্রা বাফার ছাড়া একটি প্রস্থান সিস্টেম কল করতে, এবং তারপর এটি একটি newline ছাড়া শূন্য বার প্রিন্ট করা হবে হবে। ( প্রস্থান ( এবং ) এর সিস্কল বাস্তবায়ন কীভাবে আসুন _exit (0) (সিস্কেল দ্বারা প্রস্থান করা) আমাকে কোনও স্টাডআউট সামগ্রী পেতে বাধা দেয়? )। অথবা আপনি প্রোগ্রাম 1 কে পাইপ করতে পারেন catবা এটি একটি ফাইলে পুনর্নির্দেশ করতে পারেন এবং এটি 8 বার মুদ্রিত হতে দেখুন। (স্টাডিআউট এটি টিটিওয়াই না হলে ডিফল্টরূপে পূর্ণ-বাফার হয়)। বা fflush(stdout)২ য় fork()... এর আগে নো-নিউলাইন কেসটিতে একটি যুক্ত করুন ...
পিটার কর্ডেস

17

এটি কোনওভাবেই কাঁটাচামচকে প্রভাবিত করে না।

প্রথম ক্ষেত্রে, আপনি লেখার মতো কিছুই না করে 8 টি প্রক্রিয়া শেষ করেছেন, কারণ আউটপুট বাফারটি ইতিমধ্যে খালি হয়ে গেছে (এর কারণে \n)।

দ্বিতীয় ক্ষেত্রে আপনার কাছে এখনও 8 টি প্রক্রিয়া রয়েছে, প্রতিটিতে "হ্যালো ওয়ার্ল্ড ..." সম্বলিত একটি বাফার রয়েছে এবং বাফারটি প্রক্রিয়া শেষে লেখা হয়।


12

@ কুসালানন্দ ব্যাখ্যা করলেন কেন আউটপুট পুনরাবৃত্তি হয় । যদি আপনি আগ্রহী হন তবে আউটপুটটি কেন 8 বার পুনরাবৃত্তি করা হয় এবং কেবল 4 বার নয় (বেস প্রোগ্রাম + 3 কাঁটাচামচ):

int main()
{
    printf("hello world...");
    fork(); // here it creates a copy of itself --> 2 instances
    fork(); // each of the 2 instances creates another copy of itself --> 4 instances
    fork(); // each of the 4 instances creates another copy of itself --> 8 instances
}

2
এটি কাঁটাচামানের প্রাথমিক
প্রভাটি_যাদভ

3
@ ডেবিয়ান_ইয়াদভ সম্ভবত তখনই সুস্পষ্ট, যদি আপনি এর প্রভাবগুলির সাথে পরিচিত হন। উদাহরণস্বরূপ, ফ্ল্যাশিং স্টডিও বাফারগুলির মতো ।
রোয়াইমা

2
@Debian_yadav: en.wikipedia.org/wiki/False_consensus_effect - কেন আমরা প্রশ্ন যদি সবাই সবকিছু জানেন জিজ্ঞেস করা উচিত?
হনজা জিদেক

8
@ ডেবিয়ান_ইয়াদভ আমি ওপির মনটি পড়তে পারি না তাই জানি না। যাইহোক, স্ট্যাকেক্সচেঞ্জ এমন একটি জায়গা যেখানে অন্যরাও জ্ঞানের সন্ধান করে এবং আমি মনে করি আমার উত্তরটি কুলাসন্দ্রের উত্তরের উত্তরের জন্য একটি দরকারী সংযোজন হতে পারে। আমার উত্তরটি এডিসি 65 এর সাথে তুলনা করে কিছু (মৌলিক তবে দরকারী) যুক্ত করেছে যা কুলসন্দ্র তার আগে 2 ঘন্টা আগে যা বলেছিল তার পুনরাবৃত্তি করে।
হুনজা জিদেক

2
এটি একটি উত্তর সম্পর্কে একটি সংক্ষিপ্ত মন্তব্য, আসল উত্তর নয়। প্রশ্নটি "একাধিক বার" সম্পর্কে জিজ্ঞাসা করে কেন এটি ঠিক আটটি নয়
পাইপ

3

এখানে গুরুত্বপূর্ণ ব্যাকগ্রাউন্ডটি হ'ল ডিফল্ট সেটআপ হিসাবে স্ট্যান্ডার্ড দ্বারা লাইন বাফারstdout করা প্রয়োজন ।

এর ফলে \nআউটপুট ফ্লাশ হয়।

যেহেতু দ্বিতীয় উদাহরণটিতে নতুন লাইন থাকে না, আউটপুটটি ফ্লাশ হয় না এবং fork()পুরো প্রক্রিয়াটি অনুলিপি করার ফলে এটি stdoutবাফারের অবস্থার অনুলিপি করে ।

এখন, fork()আপনার উদাহরণগুলিতে এই কলগুলি মোট 8 টি প্রক্রিয়া তৈরি করে - এগুলি সমস্ত stdoutবাফারের অনুলিপি সহ ।

সংজ্ঞা অনুসারে, এই সমস্ত প্রক্রিয়াগুলি কল exit()থেকে ফিরে আসে main()এবং সমস্ত সক্রিয় স্টাডিও স্ট্রিমগুলির পরে exit()কল আসে । এটি অন্তর্ভুক্ত করে এবং ফলস্বরূপ, আপনি একই সামগ্রীটি আটবার দেখতে পান।fflush()fclose()stdout

কল fflush()করার আগে মুলতুবি আউটপুট সহ সমস্ত স্ট্রিমগুলিতে কল করা fork()বা ফোর্কড চাইল্ডকে স্পষ্টভাবে কল করতে দেওয়া উচিত _exit()যা কেবল স্টডিও স্ট্রিমগুলি ফ্লাশ না করেই প্রক্রিয়াটি থেকে বেরিয়ে আসে।

দ্রষ্টব্য যে কলিং exec()স্টডিও বাফারগুলিকে ফ্লাশ করে না, সুতরাং আপনি যদি fork()কল করার পরে exec()( কল করার পরে ) কল করেন এবং (যদি এটি ব্যর্থ হয়) কল করেন তবে স্টিডিও বাফারদের যত্ন নেওয়া ঠিক নয় _exit()

বিটিডাব্লু: ভুল বাফারিংয়ের কারণ হতে পারে তা বোঝার জন্য, এখানে লিনাক্সের একটি পূর্ববর্তী বাগ যা সম্প্রতি ঠিক করা হয়েছে:

স্ট্যান্ডার্ডটিকে পাইপের মাধ্যমে পুনঃনির্দেশিত stderrকরা হলে লিনাক্সটি এটিকে উপেক্ষা করে stderrলাইন বার্ফার করে এবং (আরও খারাপ) পুরোপুরি বাফার করে। সুতরাং ইউনিক্সের জন্য লিখিত প্রোগ্রামগুলি লিনাক্সে খুব দেরীতে নতুন লাইন ছাড়াই আউটপুট স্টাফ করে।

নীচে মন্তব্য দেখুন, এটি এখন ঠিক করা হয়েছে বলে মনে হচ্ছে।

এই লিনাক্স সমস্যাটি ঘিরে কাজ করার জন্য আমি এটি করি:

    /* 
     * Linux comes with a broken libc that makes "stderr" buffered even 
     * though POSIX requires "stderr" to be never "fully buffered". 
     * As a result, we would get garbled output once our fork()d child 
     * calls exit(). We work around the Linux bug by calling fflush() 
     * before fork()ing. 
     */ 
    fflush(stderr); 

এই কোডটি অন্য প্ল্যাটফর্মগুলিতে ক্ষতি করে না যেহেতু fflush()কেবল প্রবাহিত স্ট্রিমে কল করা একটি নূপুর।


2
না, স্ট্যাডআউটকে সম্পূর্ণরূপে বাফার করা প্রয়োজন যদি না এটি ইন্টারেক্টিভ ডিভাইস হয় তবে এটি অনির্দিষ্ট করা না হয় তবে বাস্তবে এটি লাইন-বাফার হয়। stderr সম্পূর্ণ বাফার না করা প্রয়োজন। Pubs.opengroup.org/onlinepubs/9699919799.2018 অধিবেশন
স্টাফেন

আমার ম্যান পেজটির জন্য setbuf(), ডেবিয়ানে ( man7.org এর একটি দেখতে একই রকম ), উল্লেখ করেছে যে "স্ট্যান্ডার্ড ত্রুটি স্ট্রিম স্ট্যান্ডার সর্বদা ডিফল্টরূপে উদাসীন থাকে।" এবং একটি সহজ পরীক্ষা আউটপুট কোনও ফাইল, পাইপ বা টার্মিনালে যায় কিনা তা বিবেচনা না করেই সেভাবে কাজ করে। সি লাইব্রেরির কোন সংস্করণ অন্যথায় করবে সে সম্পর্কে আপনার কাছে কি কোনও রেফারেন্স রয়েছে?
ilkkachu

4
লিনাক্স একটি কার্নেল, স্টডিও বাফারিং একটি ইউজারল্যান্ড বৈশিষ্ট্য, কার্নেলটি সেখানে জড়িত নেই। লিনাক্স কার্নেলগুলির জন্য অনেকগুলি libc বাস্তবায়ন উপলব্ধ, সার্ভার / ওয়ার্কস্টেশন-ধরণের সিস্টেমে সর্বাধিক সাধারণ হল GNU বাস্তবায়ন, যার সাহায্যে stdout পূর্ণ-বাফার হয় (tty হলে লাইন বাফার করা হয়), এবং স্টারডার অবিফলিত হয়।
স্টাফেন চেজেলাস

1
@ দক্ষতার সাথে, কেবলমাত্র আমি পরীক্ষা চালিয়েছি : পেস্ট.ডি.ফি / এক্সক 4 । আমি খুব ভয়াবহভাবে পুরানো সিস্টেমের সাথে একই ফলাফল পেয়েছি।
ইলক্কাচু

1
@ শচিলি এটি সত্য নয় উদাহরণস্বরূপ, আমি আলপাইন লিনাক্স ব্যবহার করে এই মন্তব্যটি লিখছি, যা পরিবর্তে মসল ব্যবহার করে।
নিডজেজেকোব
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.