سؤال

بعد فتح أنبوب لعملية مع popen, ، هل هناك طريقة لقتل العملية التي بدأت؟ (استخدام pclose ليس ما أريده لأن ذلك سينتظر حتى تنتهي العملية ، لكنني بحاجة إلى قتلها.)

هل كانت مفيدة؟

المحلول

لا تستخدم popen () ، واكتب الغلاف الخاص بك الذي يفعل ما تريد.

من السهل إلى حد ما لشوكة () ، ثم استبدل stdin & stdout باستخدام DUP2 () ، ثم استدعاء exec () على طفلك.

وبهذه الطريقة ، سيكون لدى والديك رعاية الطفل الدقيقة ، ويمكنك استخدام Kill () في ذلك.

ابحث Google عن "Popen2 () تطبيق" لبعض رمز النماذج حول كيفية تنفيذ ما تفعله Popen (). إنه فقط عشرات الخطوط أو نحو ذلك. مأخوذ من dzone.com يمكننا أن نرى مثالًا يشبه هذا:

#define READ 0
#define WRITE 1

pid_t
popen2(const char *command, int *infp, int *outfp)
{
    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
        return -1;

    pid = fork();

    if (pid < 0)
        return pid;
    else if (pid == 0)
    {
        close(p_stdin[WRITE]);
        dup2(p_stdin[READ], READ);
        close(p_stdout[READ]);
        dup2(p_stdout[WRITE], WRITE);

        execl("/bin/sh", "sh", "-c", command, NULL);
        perror("execl");
        exit(1);
    }

    if (infp == NULL)
        close(p_stdin[WRITE]);
    else
        *infp = p_stdin[WRITE];

    if (outfp == NULL)
        close(p_stdout[READ]);
    else
        *outfp = p_stdout[READ];

    return pid;
}

NB: يبدو أن popen2 () هو ما تريده ، ولكن يبدو أن توزيعاتي لا يأتي مع هذه الطريقة.

نصائح أخرى

فيما يلي نسخة محسّنة من popen2 (الائتمان يرجع إلى سيرجي L.). لا يعيد الإصدار المنشور بواسطة Slacy PID من العملية التي تم إنشاؤها في POPEN2 ، ولكن PID تم تعيينها sh.

pid_t popen2(const char **command, int *infp, int *outfp)
{
    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
        return -1;

    pid = fork();

    if (pid < 0)
        return pid;
    else if (pid == 0)
    {
        close(p_stdin[WRITE]);
        dup2(p_stdin[READ], READ);
        close(p_stdout[READ]);
        dup2(p_stdout[WRITE], WRITE);

        execvp(*command, command);
        perror("execvp");
        exit(1);
    }

    if (infp == NULL)
        close(p_stdin[WRITE]);
    else
        *infp = p_stdin[WRITE];

    if (outfp == NULL)
        close(p_stdout[READ]);
    else
        *outfp = p_stdout[READ];

    return pid;
}

النسخة الجديدة يجب استدعاؤها مع

char *command[] = {"program", "arg1", "arg2", ..., NULL};

لا يبدأ Popen بالفعل موضوعًا ، بل يتقدم بعملية. عندما أنظر إلى التعريف ، لا يبدو أن هناك طريقة سهلة للحصول على هذه العملية وقتلها. قد تكون هناك طرق صعبة مثل فحص شجرة العمليات ، لكنني أعتقد أنك ستكون أفضل حالًا باستخدام وظائف الأنابيب والشوكة و EXEC لتقليد سلوك Popen. ثم يمكنك استخدام PID التي تحصل عليها من Fork () لقتل عملية الطفل.

في الواقع إذا كانت العملية تفعل I/O (والتي يجب أن تكون ، وإلا لماذا popen بدلاً من system(3)؟) ، ثم pclose يجب أن تضربها مع SIGPIPE في المرة القادمة التي تحاول القراءة أو الكتابة ، ويجب أن تسقط بشكل جيد :-)

لقد اتبعت فكرة @slacy التي تنشئ وظيفة popen2.
ولكن وجدت مشكلة عندما تكون عملية الطفل تموت ، عملية الوالدين التي لا تزال تقرأ وصف الملف outfp لا تعود من الوظيفة.

يمكن أن إصلاح عن طريق إضافة أنبوب unuse على عملية الأصل.

close(p_stdin[READ]);
close(p_stdout[WRITE]);

يمكننا الحصول على PID الصحيحة من عملية جديدة باستخدام Bash كما Shell.

execl("/bin/bash", "bash", "-c", command, NULL);

عندما يموت عملية الطفل المتصل بالوظيفة popen2 يجب جمع حالة عملية الطفل عن طريق الاتصال pclose2. إذا لم نجمع هذه الحالة ، فقد تكون عملية الطفل عملية Zombie عند إنهاءها.

هذا هو الرمز الكامل الذي اختبر ويعمل كما يتوقع.

#define READ 0
#define WRITE 1

pid_t
popen2(const char *command, int *infp, int *outfp)
{
    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
        return -1;

    pid = fork();

    if (pid < 0)
        return pid;
    else if (pid == 0)
    {
        dup2(p_stdin[READ], STDIN_FILENO);
        dup2(p_stdout[WRITE], STDOUT_FILENO);

     //close unuse descriptors on child process.
     close(p_stdin[READ]);
     close(p_stdin[WRITE]);
     close(p_stdout[READ]);
     close(p_stdout[WRITE]);

        //can change to any exec* function family.
        execl("/bin/bash", "bash", "-c", command, NULL);
        perror("execl");
        exit(1);
    }

    // close unused descriptors on parent process.
    close(p_stdin[READ]);
    close(p_stdout[WRITE]);

    if (infp == NULL)
        close(p_stdin[WRITE]);
    else
        *infp = p_stdin[WRITE];

    if (outfp == NULL)
        close(p_stdout[READ]);
    else
        *outfp = p_stdout[READ];

    return pid;
}

int
pclose2(pid_t pid) {
    int internal_stat;
    waitpid(pid, &internal_stat, 0);
    return WEXITSTATUS(internal_stat);
}

الطريقة الواضحة هي النظام ("pkill process_name") ؛

من الواضح أن هذا يمثل مشكلة إذا كان لديك أكثر من مثيل واحد من العملية التي تعمل.

لقد فعلت شيئًا مشابهًا في بيثون ، حيث يمكنك قتل عملية فرعية وأي عمليات تفوق على ذلك. إنه يشبه حل Slacy في الواقع.http://www.pixelbeat.org/libs/subprocess.py

أنا ببساطة وضعت في السيناريو (باش) ، في السطر الأول:

echo PID $$

ثم قرأت PID ، وأستخدمه للقيام A: Kill (PID ، 9)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top