当前位置: 首页 > news >正文

网站建设方案 云盘/重庆人社培训网

网站建设方案 云盘,重庆人社培训网,风景网页设计图片,什么是网络设计原则前言 在操作系统中,每个进程都有自己的进程ID(PID),父进程ID(PPID)等信息。如果一个进程已经退出,但它的、它的资源和状态还留在系统中,这种进程被称为“僵尸进程”。僵尸进程不占用CPU时间和内存资源,但它们占用系统…

前言

在操作系统中,每个进程都有自己的进程ID(PID),父进程ID(PPID)等信息。如果一个进程已经退出,但它的、它的资源和状态还留在系统中,这种进程被称为“僵尸进程”。僵尸进程不占用CPU时间和内存资源,但它们占用系统的进程表,因此可以说是一种资源泄漏。

正确处理僵尸进程

通常,进程在完成任务之后会向其父进程发送一个信号(SIGCHLD),表示自己已经退出。如果父进程没有正确地处理这个信号,会导致子进程沦为僵尸进程。因此,解决僵尸进程的方法通常是确保正确处理SIGCHLD信号。

以下是一些手动处理僵尸进程的方法:

1. 杀死父进程:如果一个进程的父进程已经退出,这个进程会被自动分配给PID=1的进程(通常是init)作为父进程。在这种情况下,如果你杀死PID=1的进程,所有的僵尸进程将被清除。

2. 重启服务:某些服务可能会创建僵尸进程,因此重启服务可以清除它们。

3. 使用kill命令:可以使用kill命令杀死僵尸进程。首先需要使用pstree命令获取僵尸进程的父进程PID,然后使用kill来杀死它。

```
pstree <zombie-pid>  
kill -9 <parent-pid>  
```

4. 编写清理脚本:可以编写一个脚本来定期扫描系统中的僵尸进程并将它们清理掉。

实际应用

处理syscall.SIGCHLD

syscall.SIGCHLD是一个信号常量,表示子进程状态发生变化,例如子进程终止或暂停等。在Unix/Linux系统中,当子进程状态发生变化时,内核会向父进程发送SIGCHLD信号,以通知父进程子进程已经发生了变化。父进程可以通过捕获SIGCHLD信号来获知子进程状态的变化,并采取相应的措施。常用的处理方式是调用wait或waitpid函数,以获取子进程的退出状态。

在Go中,如果子进程被挂起且父进程没有调用wait或waitpid函数来回收子进程,那么该子进程就会成为一个僵尸进程。为了避免僵尸进程的产生,可以通过使用os/exec包中的Cmd.Wait方法来等待子进程的退出并回收资源,如下所示:

cmd := exec.Command("your command")
err := cmd.Start()
if err != nil {// handle error
}// 等待子进程退出并回收资源
err = cmd.Wait()
if err != nil {// handle error
}

在调用Wait方法时,Go会阻塞当前goroutine,直到被等待的进程退出并回收资源。当子进程退出时,操作系统会向父进程发送SIGCHLD信号,父进程会在等待过程中捕获此信号并回收子进程资源。

如果需要处理多个子进程,可以使用go语句在单独的goroutine中运行wait函数,在主goroutine中处理其他任务,如下所示:

cmd := exec.Command("your command")
err := cmd.Start()
if err != nil {// handle error
}// 在单独的goroutine中等待子进程退出并回收资源
go func() {err = cmd.Wait()if err != nil {// handle error}
}()// 处理其他任务

通过在单独的goroutine中等待子进程退出,可以避免阻塞主goroutine的执行。当子进程退出时,wait函数会自动回收子进程的资源,避免了僵尸进程的产生。

设置子进程的系统属性

在Go语言中,如果需要设置子进程的系统属性,可以使用`os/exec`包中的`Cmd.SysProcAttr`字段,该字段的类型为`*syscall.SysProcAttr`。通过设置`Cmd.SysProcAttr`字段,可以设置子进程的属性。其中可设置的子进程属性包括信号处理方式、进程组、环境变量等。`Cmd.SysProcAttr`字段的默认值为nil,表示继承父进程的属性。

如果需要在子进程中禁用Ctrl+C信号,可以使用下面的代码:

cmd := exec.Command("your command")
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true, // 创建新进程组,以便Ctrl+C信号不会被传递到子进程
}
err := cmd.Start()
if err != nil {// handle error
}// 等待子进程退出并回收资源
err = cmd.Wait()
if err != nil {// handle error
}

在上述代码中,通过设置`syscall.SysProcAttr`结构体中的`Setpgid`字段为`true`来创建一个新的进程组,以便Ctrl+C信号不会被传递到子进程。

设置进程组ID

在Go语言中,如果需要在子进程中设置进程组ID,可以使用`os/exec`包中的`Cmd.SysProcAttr`字段,该字段的类型为`*syscall.SysProcAttr`。通过设置`Cmd.SysProcAttr`字段的`Pgid`字段,可以设置子进程的进程组ID。如果不设置`Pgid`字段,则子进程会继承父进程的进程组ID。

下面的代码演示了如何在创建子进程时设置子进程的进程组ID:

cmd := exec.Command("your command")
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true, // 创建新进程组,在新的进程组中运行子进程Pgid:    id,   // 设置进程组ID
}
err := cmd.Start()
if err != nil {// handle error
}// 等待子进程退出并回收资源
err = cmd.Wait()
if err != nil {// handle error
}

在上述代码中,通过设置`syscall.SysProcAttr`结构体中的`Setpgid`字段为`true`来创建一个新的进程组,以便子进程在新的进程组中运行。同时,通过设置`Pgid`字段,可以将子进程添加到指定的进程组中。

注意,设置进程组ID时需要保证指定的进程组ID不存在,否则会设置失败。一般来说,可以使用当前进程的进程组ID作为子进程的进程组ID。可以使用`syscall.Getpgid()`函数获取当前进程的进程组ID。

一个完整demo

在Go语言中,可以使用`syscall.Wait4()`函数来等待子进程退出并回收资源。该函数的第一个参数为子进程的进程ID,如果传入-1则表示等待任意一个子进程退出。第二个参数为传出参数,用于存储子进程的状态信息。第三个参数为附加选项,如果设置为`syscall.WNOHANG`则表示非阻塞模式,即立即返回,不等待子进程退出。如果不设置该选项,则函数会一直阻塞,直到子进程退出。第四个参数为资源使用信息,可以设置为nil。

下面的代码演示了如何使用`syscall.Wait4(-1, &ws, syscall.WNOHANG, nil)`函数来获取任意一个子进程的状态信息:

package mainimport ("fmt""syscall""time"
)func main() {// 创建多个子进程for i := 0; i < 10; i++ {go func() {time.Sleep(1 * time.Second)}()}// 等待任意一个子进程退出并回收资源var ws syscall.WaitStatuspid, _ := syscall.Wait4(-1, &ws, syscall.WNOHANG, nil)if pid > 0 {if ws.Exited() {exitStatus := ws.ExitStatus()fmt.Printf("子进程 %d 退出,退出状态码:%d\n", pid, exitStatus)} else if ws.Signaled() {signal := ws.Signal()fmt.Printf("子进程 %d 收到信号:%d\n", pid, signal)} else {fmt.Printf("子进程 %d 退出,但状态未知\n", pid)}} else {fmt.Println("没有子进程退出")}
}

在上述代码中,通过`syscall.Wait4(-1, &ws, syscall.WNOHANG, nil)`函数等待任意一个子进程退出并回收资源,并根据子进程的退出状态打印相应的信息。如果没有任何子进程退出,则打印提示信息。由于设置了`syscall.WNOHANG`选项,函数会立即返回,不会阻塞等待。需要注意的是,在多个子进程中,由于子进程退出的顺序是未知的,因此不能确定到底哪个子进程会先退出。

结合之前文章 : golang实现守护进程(2)_golang创建守护进程_dkjhl的博客-CSDN博客

// ------------------------ 守护进程 start ------------------------global.G_LOG.Info(fmt.Sprintf("os.args is %v", os.Args))
join := strings.Join(os.Args, "")if !strings.Contains(join, "-daemon") {isE, ierr := utils.CheckProRunning("go_start | grep daemon")if ierr != nil {global.G_LOG.Error("check daemon process failed, " + ierr.Error())return}if isE {global.G_LOG.Info("daemon process exist!")} else {global.G_LOG.Info("start daemon process branch...")// 启动守护进程cmd := exec.Command(os.Args[0], "-c", argv.config, "-chost", argv.chHost, "-daemon")cmd.Stdin = os.Stdincmd.Stdout = os.Stdoutcmd.Stderr = os.Stderrstrerr := cmd.Start()if strerr != nil {global.G_LOG.Error("start daemon process fail," + strerr.Error())return}global.G_LOG.Info("start daemon process success!")time.Sleep(time.Second * 2)isDae, daeErr := utils.CheckProRunning("go_start | grep daemon")if daeErr != nil {global.G_LOG.Error("check daemon process failed, " + daeErr.Error())return}if isDae {daePid := cmd.Process.Pidglobal.G_LOG.Info(fmt.Sprintf("start daemon process success, pid is %d", daePid))return} else {global.G_LOG.Error("warning! start daemon process fail...")}}
}join = strings.Join(os.Args, "")
if strings.Contains(join, "-daemon") {for {exist, checkerr := utils.CheckProRunning("go_start | grep business")if checkerr != nil {global.G_LOG.Error("check business failed, " + checkerr.Error())return}if exist {global.G_LOG.Info("business process exist!")time.Sleep(time.Second * 5)continue}global.G_LOG.Info("start business process branch...")command := exec.Command(fmt.Sprintf(path, "-business", "-c", argv.config, "-chost", argv.chHost))command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true, // 创建新进程组,以便Ctrl+C信号不会被传递到子进程}// 设置命令输出和错误输出都打印到主进程的终端command.Stdin = os.Stdincommand.Stdout = os.Stdoutcommand.Stderr = os.Stderrif comerr := command.Start(); comerr != nil {global.G_LOG.Error("start business process failed, " + comerr.Error())return}// 父进程等待子进程完成并回收子进程,处理僵尸进程;os.exec命令自带回收僵尸进程逻辑,需要调用Wait()方法werr := command.Wait()if werr != nil {global.G_LOG.Error(fmt.Sprintf("wait sub process collect error: %s", werr.Error()))}time.Sleep(time.Second * 5)exist, checkerr = utils.CheckProRunning("go_start | grep business")if checkerr != nil {global.G_LOG.Error("check business process failed, " + checkerr.Error())return}if exist {businessPid := command.Process.Pidglobal.G_LOG.Info(fmt.Sprintf("start business process suceess, pid is %d", businessPid))} else {global.G_LOG.Error("warning! start business process fail...")}}
}

上述代码,在原先的基础上,子进程启动时,添加了【父进程等待子进程完成并回收子进程,处理僵尸进程;os.exec命令自带回收僵尸进程逻辑,需要调用Wait()方法】,真正解决僵尸进程,此时程序启动,调用kill 子进程id,不会出现僵尸进程,kill 父进程id,整个进程组结束

结论

要避免僵尸进程问题,最好的方法是及时处理SIGCHLD信号。如果您正在编写应用程序,它需要管理子进程,并且需要忽略SIGCHLD信号,则可以将SIGCHLD的行为设置为SIG_IGN,指示内核自动清理终止的子进程。

http://www.jmfq.cn/news/4859515.html

相关文章:

  • 做轴承生意的网站/软件推广怎么赚钱
  • 淄博百度网站/营销策划方案怎么做
  • 设计建网站/网站建设与管理
  • 湖南做网站 干净磐石网络/百度网站提交入口网址
  • 中山排名推广/无忧seo博客
  • 广州网站优化服务/百度pc网页版
  • DW做网站下拉列表怎么做/武汉网站快速排名提升
  • 导购网站自己做电商/搜索引擎营销的优势和劣势
  • 潮州网站seo推广/网站推广的策略
  • 企业网站不付服务费应该怎么做/正规软件开发培训学校
  • 西安网站建设联系方式/徐州网站建设方案优化
  • 惠济郑州网站建设/网站策划方案案例
  • 怀化物流网站建设报价/正规的微信推广平台
  • 佛山做外贸网站的公司/互联网营销方法有哪些
  • 智慧团建管理员登录入口/百度关键词优化词精灵
  • wordpress站点前台请求数过多/设计师培训班多少钱
  • 网站建设与网页设计从入门到精通/申请网站域名要多少钱
  • 网站分类标准/东莞疫情最新消息
  • 西安网站设计与建设/网络营销推广的手段
  • 购物网站线下推广方案/单页面seo搜索引擎优化
  • 做外贸那个网站比较好/青岛seo杭州厂商
  • 电子政务与网站建设的经验/会计培训班多少钱
  • 阿里巴巴做网站费用计入/宁波seo网站推广
  • 滕州做网站的多少/互联网广告联盟
  • 哪个网站可以做片头/东莞市优速网络科技有限公司
  • 二级域名怎么做网站备案/阿里云建站
  • 石家庄小程序开发多少钱/seosem是指什么意思
  • php网站开发建设/国家大事新闻近三天
  • 高端品牌网站建设方案/提供seo顾问服务适合的对象是
  • dreamweaver学生用哪个版本/谷歌seo网站优化