2015-10-16 5 views
2

Я заметил, что процессы, начатые с exec.Command, прерываются, даже когда вызов прерывания перехвачен через signal.Notify. Я сделал следующий пример, чтобы показать проблему:Предотвращение прерывания Ctrl + C от exec.Command в Golang

package main 

import (
    "log" 
    "os" 
    "os/exec" 
    "os/signal" 
    "syscall" 
) 

func sleep() { 
    log.Println("Sleep start") 
    cmd := exec.Command("sleep", "60") 
    cmd.Run() 
    log.Println("Sleep stop") 
} 

func main() { 
    var doneChannel = make(chan bool) 

    go sleep() 

    c := make(chan os.Signal, 1) 
    signal.Notify(c, os.Interrupt) 
    signal.Notify(c, syscall.SIGTERM) 
    go func() { 
     <-c 
     log.Println("Receved Ctrl + C") 
    }() 

    <-doneChannel 
} 

Если Ctrl + C, при нажатии эта программа работает, он будет печатать:

2015/10/16 10:05:50 Sleep start 
^C2015/10/16 10:05:52 Receved Ctrl + C 
2015/10/16 10:05:52 Sleep stop 

показывает, что sleep команды прерывается , Ctrl + C успешно пойман, и основная программа не уходит, это только команды sleep.

Любая идея, как предотвратить это?

ответ

5

Оболочка будет сигнализировать всю группу процессов, когда вы нажимаете ctrl+c. Если вы сообщаете родительский процесс напрямую, дочерний процесс не получит сигнал.

Чтобы предотвратить скорлупу от сигнализации детей, вы должны начать команду в своей собственной группе процессов с с полями Setpgid и Pgid в syscall.SysProcAttr перед началом процессов

cmd := exec.Command("sleep", "60") 
cmd.SysProcAttr = &syscall.SysProcAttr{ 
    Setpgid: true, 
} 
+0

Это не работает для окон, поскольку в 'SysProcAttr' под окнами нет' Setpgid'. Любые альтернативы? – tkausl

1

Вы можете игнорировать syscall.SIGINT сигнал , то он не будет передан в exec.Command.

func main() { 
    var doneChannel = make(chan bool) 

    signal.Ignore(syscall.SIGINT) 

    go func() { 
     log.Println("Sleep start") 
     cmd := exec.Command("sleep", "10") 
     cmd.Run() 
     log.Println("Sleep stop") 
     doneChannel <- true 
    }() 

    <-doneChannel 
}