Go语言学习之signal(二)
来源:互联网 发布:mac万得股票机构 编辑:程序博客网 时间:2024/06/15 02:31
package mainimport ( "bytes" "errors" "fmt" "io" "os" "os/exec" "os/signal" "runtime/debug" "strconv" "strings" "sync" "syscall" "time")func main() { go func() { time.Sleep(5 * time.Second) sendSignal() }() handleSignal()}func handleSignal() {/* 这里先后调用了两次signal.Notify函数, 第一次调用时设定的信号集合中包含SIGINT,SINGQUIT两个信号 第二次调用时只设定了SIGQUIT一个信号 如果当前进程接收的时SIGQUIT信号,则分别发送给sigRecv1和sigRecv2两个通道 如果接收到的时SIGINT信号,则只发送给sigRecv1这一个通道*/ sigRecv1 := make(chan os.Signal, 1) sigs1 := []os.Signal{syscall.SIGILL, syscall.SIGQUIT} fmt.Printf("Set notfication for %s...[sigRecv1]\n", sigs1) signal.Notify(sigRecv1, sigs1...) sigRecv2 := make(chan os.Signal, 1) sigs2 := []os.Signal{syscall.SIGQUIT} fmt.Printf("Set notification for %s...[sigRecv2]\n", sigs2) signal.Notify(sigRecv2, sigs2...)/* sync,WaitGroup类型值wg的Add方法。添加了一个类型值为2的差量,然后在每段并发程序后面, 分别调用了wg的Done方法,该发放可以视为使差量减1, 在最后,还应该调用wg的Wait方法,该方法 会一直阻塞, 知道差量变为0*/ var wg sync.WaitGroup wg.Add(2) go func() { for sig := range sigRecv1 { fmt.Printf("Received a signal from sigRecv1: %s\n", sig) } fmt.Printf("End. [sigRecv1]\n") wg.Done() }() go func() { for sig := range sigRecv2 { fmt.Printf("Received a signal from sigRecv2: %s\n", sig) } fmt.Printf("End. [sigRecv2]\n") wg.Done() }() fmt.Println("Wait for 2 seconds... ") time.Sleep(2 * time.Second) fmt.Printf("Stop notification...") signal.Stop(sigRecv1) close(sigRecv1) fmt.Printf("done. [SigRecv1]\n") wg.Wait()}func sendSignal() { defer func() { if err := recover(); err != nil { fmt.Printf("Fatal Error: %s\n", err) debug.PrintStack() } }() cmds := []*exec.Cmd{ exec.Command("ps", "aux"), exec.Command("grep", "signal"), exec.Command("grep", "-v", "grep"), exec.Command("grep", "-v", "go run"), exec.Command("awk", "{print $2}"), } output, err := runCmds(cmds) if err != nil { fmt.Printf("Command Execution Error:", err) return } pids, err := getPids(output) if err != nil { fmt.Printf("PID Parsing Error: %s\n", err) return } fmt.Printf("Target PID(s):\n%v\n", pids) for _, pid := range pids { proc, err := os.FindProcess(pid) if err != nil { fmt.Printf("Process Finding Error: %s\n", err) return } sig := syscall.SIGQUIT fmt.Printf("Send signal '%s' to the process (pid=%d)...\n", sig, pid) err = proc.Signal(sig) if err != nil { fmt.Printf("Signal Sending Error:%s\n", err) return } }}func getPids(strs []string) ([]int, error) { var pids []int for _, str := range strs { pid, err := strconv.Atoi(strings.TrimSpace(str)) if err != nil { return nil, err } pids = append(pids, pid) } return pids, nil}func runCmds(cmds []*exec.Cmd) ([]string, error) { if cmds == nil || len(cmds) == 0 { return nil, errors.New("The cmd slice is incvalid!") } first := true var output []byte var err error for _, cmd := range cmds { fmt.Printf("Run command:%v\n", getCmdPlaintext(cmd)) if !first { var stdinBuf bytes.Buffer stdinBuf.Write(output) cmd.Stdin = &stdinBuf } var stdoutBuf bytes.Buffer cmd.Stdout = &stdoutBuf if err = cmd.Start(); err != nil { return nil, getError(err, cmd) } if err = cmd.Wait(); err != nil { return nil, getError(err, cmd) } output = stdoutBuf.Bytes() fmt.Printf("Output: \n%s\n", string(output)) if first { first = false } } var lines []string var outputBuf bytes.Buffer outputBuf.Write(output) for { line, err := outputBuf.ReadBytes('\n') if err != nil { if err == io.EOF { break } else { return nil, getError(err, nil) } } lines = append(lines, string(line)) } return lines, nil}func getCmdPlaintext(cmd *exec.Cmd) string { var buf bytes.Buffer buf.WriteString(cmd.Path) for _, arg := range cmd.Args[1:] { buf.WriteRune(' ') buf.WriteString(arg) } return buf.String()}func getError(err error, cmd *exec.Cmd, extraInfo ...string) error { var errMsg string if cmd != nil { errMsg = fmt.Sprintf("%s [%s %v]", err, (*cmd).Path, (*cmd).Args) } else { errMsg = fmt.Sprintf("%s", err) } if len(extraInfo) > 0 { errMsg = fmt.Sprintf("%s (%v)", errMsg, extraInfo) } return errors.New(errMsg)}
代码包os/signal中Notify函数用来当操作系统向当前进程发送指定信号时发出通知
func Notify(c chan<-os.Signal, sig ...os.Signal)
其中第一个参数是通道类型的,该参数的类型的chan<-os.Signal,这表示参数c是一个发送通道,在Notify函数中,只能向它发送os.Signal类型的值(以下简称信号值),而不能从中接收信号值。signal.Notify函数会把当前进程中接收到的指定信号放入参数c代表的通道类型值中,这样该函数的调用方就可以从这个signal接收通道中按顺序获取操作系统发来的信号并进行相应的处理。
第二个参数是可变长的参数,这意味着我们在调用signal.Notify函数时,可以在第一个参数值之后再附加任意个os.Signal类型的值,os/signal包中的程序会把它封装成syscall.Signal类型的值并放入到signal接收通道中。
阅读全文
1 0
- Go语言学习之signal(二)
- GO语言学习二(基础)
- go语言基础学习二
- GO语言学习笔记(二)
- Go语言学习(二)常量
- GO语言学习笔记二
- go语言学习之路(一)
- Go学习笔记(二)初试Go第一个Go语言
- Go语言KickStart——《Java程序员学习Go》之二
- go语言学习之-------go httpserver进阶之路go(2)
- Go语言学习之数据类型
- GO语言学习之goroutine
- Go语言学习笔记(二)基本数据
- go语言之beego框架orm的使用(二)
- Go语言编程(二)之编译环境
- go语言之beego框架orm的使用(二)
- go语言(二)变量
- GO语言补充(二)
- TensorFlow练习: 根据大脸判断性别和年龄
- I/O compile
- 关于在web中的数据传递
- springmvc-web.xml无法映射的问题解惑
- 19th 【最短路 floyd】租用游艇
- Go语言学习之signal(二)
- java中的native方法
- shell基础
- POJ 2602 Superlong sums G++
- 获取网易云音乐封面图片
- 12-1-系统状态检测进程控制
- 【MyBatis学习15】MyBatis的逆向工程生成代码
- SAPUI5教程——The project is corrupted because its '.user.project.json' file has an invalid JSON
- 数据库拆分的问题