সিগিন্টটি যখন তার পিতামাতার প্রক্রিয়ায় প্রেরণ করা হয় তখন কেন শিশু প্রক্রিয়ায় প্রচার করা হয় না?


62

একটি শেল প্রক্রিয়া (উদাঃ sh) এবং তার শিশু প্রক্রিয়া (উদাঃ cat) দেওয়া, আমি কীভাবে শেলের প্রক্রিয়া আইডি ব্যবহার করে Ctrl+ এর আচরণ অনুকরণ করতে পারি C?


এটি আমি চেষ্টা করেছি:

চলমান shএবং তারপরে cat:

[user@host ~]$ sh
sh-4.3$ cat
test
test

অন্য টার্মিনাল থেকে পাঠানো SIGINTহচ্ছে cat:

[user@host ~]$ kill -SIGINT $PID_OF_CAT

cat সংকেত পেয়েছে এবং সমাপ্ত হয়েছে (প্রত্যাশার মতো)।

পিতামাতার প্রক্রিয়াতে সিগন্যাল প্রেরণে কাজ হবে বলে মনে হয় না। সিগন্যালটি catযখন তার পিতামাতার প্রক্রিয়ায় প্রেরণ করা হয় তখন কেন তা প্রচার করা হয় না sh?

এটা কাজ করে না:

[user@host ~]$ kill -SIGINT $PID_OF_SH

1
কীবোর্ড বা টার্মিনাল থেকে প্রেরিত সিগন্যাল সিগন্যালগুলি উপেক্ষা করার শেলের একটি উপায় রয়েছে।
কনসোলবক্স

উত্তর:


86

কিভাবে CTRL+ Cকাজ করে

প্রথম জিনিস কিভাবে বুঝতে CTRL+ + Cকাজ করে।

আপনি যখন CTRL+ Cটিপেন, আপনার টার্মিনাল এমুলেটর একটি ETX অক্ষর প্রেরণ করে (পাঠ্যের শেষে / 0x03)।
TTY এমনটি কনফিগার করা হয় যে যখন এটি এই অক্ষরটি গ্রহণ করে, এটি টার্মিনালের অগ্রভাগ প্রক্রিয়া গোষ্ঠীতে একটি সাইন ইন প্রেরণ করে। এই কনফিগারেশনটি দেখে sttyএবং দেখেও দেখা যাবে intr = ^C;POSIX স্পেসিফিকেশন বলছেন যে যখন INTR গৃহীত হয়, এটা যে টার্মিনাল ফোরগ্রাউন্ড প্রক্রিয়া গোষ্ঠীটির একটি SIGINT পাঠাতে হবে।

অগ্রভাগ প্রক্রিয়া গ্রুপ কি?

সুতরাং, এখন প্রশ্ন হল, আপনি কীভাবে নির্ধারণ করবেন যে অগ্রভাগ প্রক্রিয়া গ্রুপটি কী? অগ্রভাগ প্রক্রিয়া গোষ্ঠীটি কেবল প্রক্রিয়াগুলির গ্রুপ যা কীবোর্ড (সিগন্যস্টপ, সাইন ইন, ইত্যাদি) দ্বারা উত্পাদিত যে কোনও সংকেত গ্রহণ করবে।

প্রক্রিয়া গ্রুপ আইডি নির্ধারণ করার সহজ উপায়টি হ'ল ps:

ps ax -O tpgid

দ্বিতীয় কলামটি হবে প্রক্রিয়া গ্রুপ আইডি।

প্রক্রিয়া গ্রুপে আমি কীভাবে একটি সংকেত পাঠাব?

প্রক্রিয়া গ্রুপ আইডি কী তা আমরা জানি এখন, আমাদের পুরো গ্রুপে একটি সংকেত প্রেরণের POSIX আচরণ অনুকরণ করা দরকার।

এটি গ্রুপ আইডির সামনে killরেখে দিয়ে করা যায় -
উদাহরণস্বরূপ, যদি আপনার প্রক্রিয়া গোষ্ঠী আইডি 1234 হয়, আপনি ব্যবহার করবেন:

kill -INT -1234

 


অনুকরণ CTRL+ Cটার্মিনাল নম্বর ব্যবহার করে।

সুতরাং উপরেরটি কীভাবে ম্যানুয়াল প্রক্রিয়া হিসাবে CTRL+ অনুকরণ করতে হয় তা কভার Cকরে। তবে আপনি যদি টিটিওয়াই নম্বরটি জানেন, এবং আপনি সেই টার্মিনালের জন্য CTRL+ অনুকরণ করতে চান C?

এটি খুব সহজ হয়ে যায়।

ধরে $ttyনেওয়া যাক আপনি যে টার্মিনালটি টার্গেট করতে চান তা (আপনি tty | sed 's#^/dev/##'টার্মিনালে চালিয়ে এটি পেতে পারেন )।

kill -INT -$(ps h -t $tty -o tpgid | uniq)

অগ্রভাগ প্রক্রিয়া গ্রুপের যাই হোক না কেন এটি সাইন ইন প্রেরণ করবে $tty


6
এটি উল্লেখ করা মূল্যবান যে টার্মিনাল বাইপাস অনুমতি চেকিং থেকে সরাসরি আসে এমন সংকেত, সুতরাং Ctrl + C সর্বদা সিগন্যাল সরবরাহ করতে সফল হয় যদি না আপনি এটি টার্মিনাল বৈশিষ্ট্যগুলিতে বন্ধ করে দেন, তবে কোনও killকমান্ড ব্যর্থ হতে পারে।
ব্রায়ান দ্বি

4
+1, এর জন্যsends a SIGINT to the foreground process group of the terminal.
অ্যান্ডি

ওয়ার্থ উল্লেখ সন্তানকে দুধ পান করানোর প্রক্রিয়া গ্রুপ পিতা বা মাতা পর হিসাবে একই fork। সর্বনিম্ন চলমান
Ciro

15

যেমন ভিনক 17 বলেছেন, এটি হওয়ার কোনও কারণ নেই। আপনি যখন একটি সিগন্যাল-উত্পন্ন কী অনুক্রম টাইপ করেন (যেমন, Ctrl+ C), টার্মিনালের সাথে সংযুক্ত (প্রাসঙ্গিক) সমস্ত প্রক্রিয়াতে সংকেত প্রেরণ করা হয়। দ্বারা উত্পাদিত সংকেতগুলির জন্য এই জাতীয় কোনও ব্যবস্থা নেই kill

তবে, একটি কমান্ড মত

kill -SIGINT -12345

প্রক্রিয়া গ্রুপ 12345 এ সমস্ত প্রক্রিয়াগুলিতে সিগন্যাল প্রেরণ করবে ; দেখুন হত্যা (1) এবং বধ (2) । শেলের শিশুরা সাধারণত শেলের প্রক্রিয়া গ্রুপে থাকে (কমপক্ষে, যদি তারা অবিচ্ছিন্ন না হয়), সুতরাং শেলের পিআইডি নেতিবাচককে সংকেত পাঠানো আপনি যা করতে পারেন তা করতে পারে।


ওহো

ভিঙ্ক ১17 হিসাবে উল্লেখ করা হয়েছে যে এটি ইন্টারেক্টিভ শেলগুলির জন্য কাজ করে না। এখানে একটি বিকল্প যা কার্যকর হতে পারে :

কিল -SIGINT - e (প্রতিধ্বনি $ (PS -p PID_of_shell o tpgid =))

ps -pPID_of_shellশেলের উপর প্রক্রিয়া সম্পর্কিত তথ্য পায়।  o tpgid=শিরোনামহীন psশুধুমাত্র টার্মিনাল প্রক্রিয়া গ্রুপ আইডি আউটপুট করতে বলে । এটি যদি 10000 এরও কম হয় তবে psএটি শীর্ষস্থানীয় স্থান (গুলি) সহ প্রদর্শিত হবে; $(echo …)একটি দ্রুত কৌতুক নেতৃস্থানীয় (এবং trailing) স্পেস বন্ধ স্ট্রিপ হয়।

আমি এটি একটি ডেবিয়ান মেশিনে কার্সারি পরীক্ষায় কাজ করতে পেরেছি।


1
প্রক্রিয়াটি ইন্টারেক্টিভ শেলটিতে শুরু হওয়ার পরে এটি কার্যকর হয় না (যা ওপি ব্যবহার করছে)। যদিও এই আচরণের জন্য আমার কাছে কোনও রেফারেন্স নেই।
ভিঙ্ক 17

12

প্রশ্নটির নিজস্ব উত্তর রয়েছে। পাঠানো হচ্ছে SIGINTথেকে catপ্রক্রিয়া killকি যখন আপনি টিপুন একটি নিখুঁত সিমুলেশন ^C

আরও সুনির্দিষ্টভাবে বলতে গেলে, বিঘ্নিত অক্ষর ( ^Cডিফল্টরূপে) SIGINTটার্মিনালের অগ্রভাগ প্রক্রিয়া গোষ্ঠীর প্রতিটি প্রক্রিয়াতে প্রেরণ করে। আপনি পরিবর্তে যদি catএকাধিক প্রক্রিয়া জড়িত আরও জটিল কমান্ড চালাচ্ছিলেন, তবে একই প্রভাব অর্জন করতে আপনাকে প্রক্রিয়া গ্রুপটিকে হত্যা করতে হবে ^C

আপনি যখন &ব্যাকগ্রাউন্ড অপারেটর ছাড়াই কোনও বাহ্যিক কমান্ড চালান , শেলটি কমান্ডের জন্য একটি নতুন প্রক্রিয়া গ্রুপ তৈরি করে এবং টার্মিনালটিকে অবহিত করে যে এই প্রক্রিয়া গ্রুপটি এখন অগ্রভাগে রয়েছে। শেলটি এখনও তার নিজস্ব প্রক্রিয়া গোষ্ঠীতে রয়েছে, যা আর পূর্বের অংশে নেই। তারপরে শেলটি কমান্ডটি প্রস্থান করার জন্য অপেক্ষা করে।

এখান থেকে আপনি একটি সাধারণ ভুল ধারণার শিকার হয়েছেন বলে মনে হয়: শেলটি তার শিশু প্রক্রিয়া (এসএস) এবং টার্মিনালের মধ্যে মিথস্ক্রিয়াটিকে সহজতর করতে কিছু করছে বলে ধারণা। এটা ঠিক সত্য নয়। এটি একবার সেটআপ কাজ করে নিলে (প্রক্রিয়া তৈরি, টার্মিনাল মোড সেটিং, পাইপ তৈরি এবং অন্যান্য ফাইল বর্ণনাকারীর পুনঃনির্দেশ এবং লক্ষ্য প্রোগ্রামটি কার্যকর করা) শেলটি কেবল অপেক্ষা করে । আপনি catযেটি টাইপ করেন তা শেলটি দিয়ে যাচ্ছে না, এটি সাধারণ ইনপুট হোক বা সিগন্যাল উত্পন্ন বিশেষ চরিত্র ^Ccatপ্রক্রিয়া নিজস্ব ফাইল বর্ণনাকারী মাধ্যমে টার্মিনাল থেকে সরাসরি প্রবেশাধিকার আছে, এবং টার্মিনাল সংকেত সরাসরি পাঠাতে করার ক্ষমতা থাকবে cat, কারণ এটি ফোরগ্রাউন্ড প্রক্রিয়া গ্রুপ প্রক্রিয়াকে।

catপ্রক্রিয়াটি মারা যাওয়ার পরে , শেলটি অবহিত করা হবে, কারণ এটি catপ্রক্রিয়াটির মূল parent তারপরে শেলটি সক্রিয় হয়ে যায় এবং নিজেকে আবার অগ্রভাগে রাখে।

আপনার বোঝাপড়া বাড়াতে এখানে একটি অনুশীলন দেওয়া হয়েছে।

নতুন টার্মিনালের শেল প্রম্পটে এই কমান্ডটি চালান:

exec cat

execশব্দ শেল চালানো ঘটায় catএকটি শিশু প্রক্রিয়া তৈরি করে। শেলটি প্রতিস্থাপন করা হয় cat। পূর্বে শেলটির সাথে সম্পর্কিত পিআইডি এখন পিআইডি catpsএটি একটি ভিন্ন টার্মিনাল দিয়ে যাচাই করুন । কিছু এলোমেলো লাইন টাইপ করুন এবং দেখুন যে catসেগুলি আপনার কাছে আবার ফিরে আসে, প্রমাণ করে যে এটি পিতামাতা হিসাবে শেল প্রক্রিয়া না থাকা সত্ত্বেও এটি এখনও স্বাভাবিকভাবে আচরণ করে। এখন চাপ দিলে কী হবে ^C?

উত্তর:

সাইন ইন বিড়াল প্রক্রিয়া বিতরণ করা হয়, যা মারা যায়। যেহেতু এটি টার্মিনালের একমাত্র প্রক্রিয়া ছিল, সেশনটি শেষ হবে ঠিক যেমন আপনি শেল প্রম্পটে "প্রস্থান" করতে চাইছেন। ফলস্বরূপ বিড়ালটি কিছুক্ষণের জন্য আপনার শেল ছিল


শেলটি শেষ হয়ে গেছে। +1
পিয়োটর ডবরোগোস্ট

আমি বুঝতে পারছি না কেন চাপ exec catদেওয়ার পরে ^Cকেবল ^Cবিড়াল হয়ে উঠবে না । কেন catএটি এখন যে শেলটি প্রতিস্থাপন করেছে তা বন্ধ করবে ? যেহেতু শেলটি প্রতিস্থাপন করা হয়েছে, শেলটি হ'ল এমন জিনিস যা পাওয়ার পরে তার বাচ্চাদের কাছে সিগিন্ট প্রেরণের যুক্তি প্রয়োগ করে ^C
স্টিভেন লু

মুল বক্তব্যটি হ'ল শেলটি তার বাচ্চাদের কাছে SIGINT প্রেরণ করে না । সিগিন্টটি টার্মিনাল ড্রাইভার থেকে আসে এবং সমস্ত অগ্রভাগের প্রক্রিয়ায় প্রেরণ করা হয়।

3

SIGINTসন্তানের কাছে প্রচার করার কোনও কারণ নেই । তবুও system()পসিএক্স স্পেসিফিকেশন বলছে: "সিস্টেম () ফাংশনটি সাইন ইন এবং সাইনকিট সিগন্যালগুলি উপেক্ষা করবে এবং কমান্ডটি সমাপ্ত হওয়ার অপেক্ষায় সাইন সিএইচএলডি সিগন্যালটি ব্লক করে দেবে।"

যদি শেল প্রাপ্তির প্রচার করে SIGINT, যেমন একটি বাস্তব সিটিআরএল-সি অনুসরণ করে, এর অর্থ হ'ল শিশু প্রক্রিয়াটি SIGINTদু'বার সংকেত গ্রহণ করবে , যার অযাচিত আচরণ থাকতে পারে।


শেলটি এটি দিয়ে প্রয়োগ করতে হবে না system()। তবে আপনি ঠিক বলেছেন, যদি এটি সিগন্যাল ধরে ফেলে (স্পষ্টভাবে এটি করে) তবে এটিকে নীচের দিকে প্রচার করার কোনও কারণ নেই।
স্বর্ণলোকস 11:58

@ গোল্ডিলক্স আমি আমার উত্তরটি সম্পূর্ণ করেছি, সম্ভবত আরও ভাল কারণ দিয়েছি। মনে রাখবেন যে শেলটি জানতে পারে না যে শিশুটি ইতিমধ্যে সংকেত পেয়েছে, তাই সমস্যা।
ভিঙ্ক 17

1

setpgid POSIX সি প্রক্রিয়া গ্রুপ ন্যূনতম উদাহরণ

অন্তর্নিহিত এপিআই এর একটি ন্যূনতম চলমান উদাহরণ দিয়ে বোঝা আরও সহজ হতে পারে।

এটি চিত্রিত করে যে কীভাবে সিগন্যালটি শিশুকে প্রেরণ করা হয়, যদি শিশু তার প্রক্রিয়া গোষ্ঠীটি পরিবর্তন না করে setpgid

main.c

#define _XOPEN_SOURCE 700
#include <assert.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

volatile sig_atomic_t is_child = 0;

void signal_handler(int sig) {
    char parent_str[] = "sigint parent\n";
    char child_str[] = "sigint child\n";
    signal(sig, signal_handler);
    if (sig == SIGINT) {
        if (is_child) {
            write(STDOUT_FILENO, child_str, sizeof(child_str) - 1);
        } else {
            write(STDOUT_FILENO, parent_str, sizeof(parent_str) - 1);
        }
    }
}

int main(int argc, char **argv) {
    pid_t pid, pgid;

    (void)argv;
    signal(SIGINT, signal_handler);
    signal(SIGUSR1, signal_handler);
    pid = fork();
    assert(pid != -1);
    if (pid == 0) {
        is_child = 1;
        if (argc > 1) {
            /* Change the pgid.
             * The new one is guaranteed to be different than the previous, which was equal to the parent's,
             * because `man setpgid` says:
             * > the child has its own unique process ID, and this PID does not match
             * > the ID of any existing process group (setpgid(2)) or session.
             */
            setpgid(0, 0);
        }
        printf("child pid, pgid = %ju, %ju\n", (uintmax_t)getpid(), (uintmax_t)getpgid(0));
        assert(kill(getppid(), SIGUSR1) == 0);
        while (1);
        exit(EXIT_SUCCESS);
    }
    /* Wait until the child sends a SIGUSR1. */
    pause();
    pgid = getpgid(0);
    printf("parent pid, pgid = %ju, %ju\n", (uintmax_t)getpid(), (uintmax_t)pgid);
    /* man kill explains that negative first argument means to send a signal to a process group. */
    kill(-pgid, SIGINT);
    while (1);
}

গিটহাব উজানের দিকে

এর সাথে সংকলন:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -Wpedantic -o setpgid setpgid.c

ছাড়া চালাও setpgid

কোনও সিএলআই আর্গুমেন্ট ছাড়া, setpgidসম্পন্ন করা হয় না:

./setpgid

সম্ভাব্য ফলাফল:

child pid, pgid = 28250, 28249
parent pid, pgid = 28249, 28249
sigint parent
sigint child

এবং প্রোগ্রাম স্থগিত।

যেমন আমরা দেখতে পাচ্ছি, উভয় প্রক্রিয়ার পিজিডিটি একইরকম, যেমন এটি উত্তরাধিকারসূত্রে প্রাপ্ত হয় fork

তারপরে আপনি যখনই আঘাত করবেন:

Ctrl + C

এটি আবার ফলাফল:

sigint parent
sigint child

এটি কীভাবে দেখায়:

  • এর সাথে একটি সম্পূর্ণ প্রক্রিয়া গোষ্ঠীতে একটি সংকেত প্রেরণ করতে kill(-pgid, SIGINT)
  • টার্মিনালের Ctrl + C ডিফল্টরূপে পুরো প্রক্রিয়া গোষ্ঠীতে একটি কিল পাঠায়

উভয় প্রক্রিয়াতে একটি পৃথক সিগন্যাল প্রেরণ করে প্রোগ্রামটি প্রস্থান করুন, উদাহরণস্বরূপ SIGQUIT দিয়ে Ctrl + \

সাথে চালাও setpgid

আপনি যদি কোনও যুক্তি দিয়ে চালনা করেন, যেমন:

./setpgid 1

তারপরে বাচ্চা তার পিজিডি পরিবর্তন করে এবং এখন কেবলমাত্র বাবা-মার কাছ থেকে প্রতিবারই একক সিগিন্ট মুদ্রিত হয়:

child pid, pgid = 16470, 16470
parent pid, pgid = 16469, 16469
sigint parent

এবং এখন, আপনি যখনই আঘাত করবেন:

Ctrl + C

কেবল পিতামাতাই সিগন্যালটি পান:

sigint parent

আপনি এখনও একটি সিকিউইটি দিয়ে পূর্বের মতো পিতামাতাকে হত্যা করতে পারেন:

Ctrl + \

তবে সন্তানের এখন আলাদা আলাদা পিজিআইডি রয়েছে, এবং সেই সংকেতটি পান না! এটি থেকে দেখা যায়:

ps aux | grep setpgid

আপনাকে এটিকে স্পষ্টভাবে হত্যা করতে হবে:

kill -9 16470

এটি সিগন্যাল গোষ্ঠী কেন বিদ্যমান তা পরিষ্কার করে দেয়: অন্যথায় আমরা সমস্ত সময় ম্যানুয়ালি পরিষ্কার করার জন্য একগুচ্ছ প্রক্রিয়াগুলি পেয়ে যাব।

উবুন্টু 18.04 এ পরীক্ষিত।

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