守护进程接收终端输入的一种变通性方法

说明

本文主要介绍某嵌入式产品中DSL用户态驱动模块作为守护进程时,如何接收终端输入的变通性方法。

出于信息安全考虑,文中涉及系统方面的接口函数未给出实现细节,但不影响表述的完整性。

相关性文章参见《GNU Readline库函数的应用示例》。

一  背景知识

init进程(如Busybox init)是嵌入式系统内核自举时启动的第一个也是惟一的用户进程。init进程是后续所有其他进程的父进程(其进程ID为1),在系统运行期间以守护进程的形式一直存在。它主要负责启动各运行层次特定的系统服务(如执行某些脚本、启动shell及运行用户指定的程序等),这些服务通常在其拥有的守护进程的帮助下实现。

Busybox init程序对应的代码在init/init.c文件中,首先启动init_main函数,以设置信号的处理函数、初始化控制台以及解析inittab内容。

守护进程没有控制终端。因此编写守护进程时,通常关闭标准输入、标准输出和标准出错等文件描述符(若不关闭会浪费系统资源,造成进程所在文件系统无法卸载甚至引起无法预料的错误)。这样,守护进程不再持有从其父进程继承而来的文件描述符,任何一个试图读标准输入、写标准输出和标准出错的库例程将不会产生任何效果。因为守护进程并不与终端设备相关联,所以不能在终端设备上显示其输出,也无处从交互式用户那里接收输入。

但某产品中因调试排障需要,未关闭标准输出描述符。事实上,该产品中所有进程均作为pc守护进程的子进程启动,但启动时并未执行关闭文件描述符的步骤,而是在Busybox的init_main函数关闭标准输入和标准出错。虽然守护进程已脱离控制终端,但仍可使用从父进程继承的文件描述符来输出到“原”终端。

此外,嵌入式系统中守护进程通常启动后一直运行直至系统关机,而不受用户输入的影响。若不关闭标准输入,虽然各守护进程可以不处理这些输入,或按需选择性地处理,但当多个进程试图读取标准输入时将引起混乱。

二  需求提出

BCM厂家SDK为该产品DSL驱动模块提供了丰富的配置、查询及调测命令集,入口函数为dispatchingTask。该函数行为类似多级Shell,内部通过BCM_GETLINE宏(循环+getchar实现)等待和捕获用户输入。其模型可简化为:

1 dispatchingTask
2 {
3     while getchar
4         若输入 == "doSomething"
5             do something
6         若输入 == "-4"
7             break
8 }

DSL驱动模块作为守护进程没有控制终端,无法通过getchar捕获终端输入。因此,必须创建一个普通的前台进程,由该进程捕获终端输入并转发给DSL驱动。但这种消息驱动的异步方式无法实现BCM_GETLINE的“同步等待”特性,还需开辟一块读写缓存。

具体实现如下图所示:

前台进程dsltst捕获用户在终端输入的命令行,并转发给DslDriver(DSL驱动)进程下的dsldbg线程。dsldbg线程若接收到BcmShell启动命令行(“StartShell”),则向dsldrv线程发送Shell启动消息;否则将命令行输入进行缓存。dsldrv线程启动BcmShell后将“轮询”该缓存,若缓存非空则读取其中的命令行并做相应处理。

注意,同一进程下线程间的消息收发通过读写一个由指向消息体数据的指针组成的循环缓冲区实现,并非传统意义上的进程间消息队列。

基于命令行交互模式的考虑,无需使用互斥机制保护缓存:

1) 每次执行单条输入并输出,等待下条输入;

2) 本次输入(写)必须等待上次输入被执行(读)并输出。

三  代码实现

为描述清晰,本节将按照代码文件组织各小节内容。

3.1 Readline.c/h

Readline.c/h为基本的命令行输入函数集。考虑到终端设备可能不支持GNU Readline库,本函数集可在需要时用来替代库的行为。

首先定义一组私有函数,如下:

 1 /******************************************************************************
 2 * 函数名称:  TerminateStr
 3 * 功能说明:  对给定字符数组添加结束符
 4 ******************************************************************************/
 5 static VOID TerminateStr(CHAR *pszStr, INT32U dwCharsNum)
 6 {
 7     if(0 == dwCharsNum)
 8         return;
 9     pszStr[dwCharsNum-1] = ‘\0‘;
10 }
11
12 /******************************************************************************
13 * 函数名称:  FlushStdin
14 * 功能说明:  清空标准输入缓冲区
15 ******************************************************************************/
16 static VOID FlushStdin(VOID)
17 {
18     INT32S cChar = 0;
19     while((cChar = getchar()) != ‘\n‘ && cChar != EOF);
20 }
21
22 /******************************************************************************
23 * 函数名称:  GetChars
24 * 功能说明:  命令行输入函数
25 * 输入参数:  CHAR *pszBuf     :字符缓冲区
26 *           INT32U dwBufSize :字符缓冲区字节大小
27 * 输出参数:  NA
28 * 返回值  :  若缓冲区空间不足,则返回-2,以指示需要扩展缓冲区或终止输入;
29 *           若函数出错且尚未输入,则返回-1;
30 *           否则返回当前调用所输入的字符数(‘\n‘被替换为‘\0‘并计入字符数)
31 * 注意事项:  Linux下该函数不支持退格键(BackSpace)消字符,请使用删除键(Delete)
32 ******************************************************************************/
33 #define LINUX_BS_KEY     (CHAR)0x08  //Unix/Linux系统BackSpace键ASCII值
34 static INT32S GetChars(CHAR *pszBuf, INT32U dwBufSize)
35 {
36     INT32U dwIdx = 0;
37     INT32S dwChar = 0;
38     for(; dwIdx<dwBufSize && (dwChar=getchar())!=EOF && dwChar!=‘\n‘; dwIdx++)
39     {
40         if(LINUX_BS_KEY == dwChar)
41         {
42             printf("Try again from scratch, use ‘Delete‘ key to BackSpace!\n");
43             FlushStdin();
44             return dwChar;
45         }
46         pszBuf[dwIdx] = dwChar;
47     }
48
49     if(dwIdx==0 && dwChar==EOF)
50         return -1;
51
52     if(dwIdx==dwBufSize && dwChar!=EOF && dwChar!=‘\n‘)
53         return -2;
54
55     if(dwChar == ‘\n‘)
56         pszBuf[dwIdx] = ‘\0‘;
57
58     return (++dwIdx);
59 }

TerminateStr()函数给字符串添加结束符,其封装性可有可无。FlushStdin()函数清空标准输入缓冲区中残留的字符。此处未采用fflush(stdin)的方式,因为C标准中fflush()函数仅针对输出流或更新流(output or update stream)。

GetChars()函数为核心的命令行输入函数,ReadLine()函数内将分配动态内存并调用该函数对外提供命令行输入功能:

 1 /******************************************************************************
 2 * 函数名称:  ReadLine
 3 * 功能说明:  命令行输入函数
 4 * 输入参数:  CHAR *pszPrompt: 命令行提示符,若无则置空字符串("")
 5 * 输出参数:  NA
 6 * 返回值  :  CHAR *已输入的命令行字符串或NULL(表示函数出错)
 7 ******************************************************************************/
 8 CHAR *ReadLine(const CHAR *pszPrompt)
 9 {
10     CHECK_SINGLE_POINTER(pszPrompt, NULL);
11
12     printf("%s", pszPrompt);
13
14     CHAR *pszLineRead = NULL;
15     INT32U dwCurAllocSize = ALLOC_BYTES_INIT_TRY;
16     INT32U dwEstReadCharNum = 0;
17     INT32S dwCharSize = 0;
18     while(1)
19     {
20         CHAR *pszReallocBuf = realloc(pszLineRead, dwCurAllocSize);
21         if(NULL == pszReallocBuf)
22         {
23             printf("[%s(%d)] reallocs %uBytes failed, no memory available!\n",
24                    FUNC_NAME, __LINE__, dwCurAllocSize);
25             goto ReadLineError;
26         }
27         pszLineRead = pszReallocBuf; //Avoid memory leakage when realloc fails.
28         dwCharSize = GetChars(pszLineRead+dwEstReadCharNum, dwCurAllocSize-dwEstReadCharNum);
29         dwEstReadCharNum = dwCurAllocSize;
30         if(-2 != dwCharSize)
31             return pszLineRead;
32
33         INCREMENT_ALLOC_BYTES(dwCurAllocSize);
34         if(dwCurAllocSize >= ALLOC_BYTES_MAX_TRY)
35         {
36             printf("\nOver %uBytes Memory‘s Required, There must be something WRONG!\n", dwCurAllocSize);
37             goto ReadLineError;
38         }
39     }
40
41 ReadLineError:
42     FlushStdin();
43     TerminateStr(pszLineRead, dwEstReadCharNum);
44     return pszLineRead;
45 }

ReadLine()函数内会为命令行缓冲区分配内存,故调用者无需再分配缓存。也正因为如此,ReadLine()函数必须考虑内存裕量问题,即必要时扩展内存以确保足够容纳终端输入的命令行。

因本文所涉产品不支持-lreadline、-lhistory甚至-lncurses库,故AddHistory实现为空函数:

 1 /******************************************************************************
 2 * 函数名称:  AddHistory
 3 * 功能说明:  将命令添加到历史记录,以支持上下键调出历史命令
 4 * 输入参数:  CHAR *pszCmd :待添加的命令
 5 * 输出参数:  NA
 6 * 返回值  :  VOID
 7 ******************************************************************************/
 8 VOID AddHistory(CHAR *pszCmd)
 9 {
10     /* Remains to be implemented! */
11 }

终端输入结束后,需调用CloseLine()函数释放ReadLine()函数分配的动态内存:

 1 /******************************************************************************
 2 * 函数名称:  CloseLine
 3 * 功能说明:  关闭命令行输入
 4 * 输入参数:  CHAR *pszLine :命令行输入字符串指针
 5 * 输出参数:  NA
 6 * 返回值  :  VOID
 7 ******************************************************************************/
 8 VOID CloseLine(CHAR *pszLine)
 9 {
10     if(!pszLine)
11         return;
12
13     free(pszLine);
14 }

为支持用户自定义ReadLine()函数的内存扩展方式,ReadLine.h头文件内定义如下宏:

 1 #ifndef ALLOC_BYTES_INIT_TRY
 2     #define ALLOC_BYTES_INIT_TRY    32    //初次尝试分配的内存字节数
 3 #endif
 4 #ifndef ALLOC_BYTES_MAX_TRY
 5     #define ALLOC_BYTES_MAX_TRY     1024  //累计尝试分配的最大内存字节数
 6 #endif
 7 #ifndef INCREMENT_ALLOC_BYTES
 8     #define INCREMENT_ALLOC_BYTES(dwCurAllocSize) do{  9             dwCurAllocSize <<= 1; 10     }while(0)
11 #endif

用户可在包含ReadLine.h头文件之前,重定义ALLOC_BYTES_INIT_TRY等宏。

3.2 Dsl_Readline.c/h

Dsl_Readline.c/h为DSL模块命令行输入函数集。

首先,根据GNU Readline库的支持情况,做如下条件编译控制:

 1 #ifdef READLINE_DEBUG
 2     #include <readline/readline.h>
 3     #include <readline/history.h>
 4     #define READ_LINE     readline
 5     #define ADD_HISTORY   add_history
 6     #define CLR_LINE      free
 7 #else
 8     #include "Readline.h"
 9     #define READ_LINE     ReadLine
10     #define ADD_HISTORY   AddHistory
11     #define CLR_LINE      CloseLine
12 #endif

然后,定义两个字符串指针:

1 static CHAR *pszLineRead = NULL;  //命令行输入字符串
2 static CHAR *pszStripLine = NULL;  //剔除首尾空白字符的输入字符串

ReadCmdLine()函数通过READ_LINE宏读取终端输入的命令行后,调用StripWhite()函数剔除命令行字符串首尾的空白字符(主要是空格符)。若剔除后的字符串非空且非空串,则通过ADD_HISTORY宏将该串存入历史记录。

 1 /******************************************************************************
 2 * 函数名称:  ReadCmdLine
 3 * 功能说明:  命令行输入函数
 4 * 输入参数:  CHAR *pszPrompt: 命令行提示符,若无则置空字符串("")
 5 * 输出参数:  NA
 6 * 返回值  :  CHAR *已输入且剔除首尾空白字符的命令行字符串
 7 ******************************************************************************/
 8 CHAR *ReadCmdLine(const CHAR *pszPrompt)
 9 {
10     CLR_LINE(pszLineRead);
11     pszLineRead = READ_LINE(pszPrompt);
12
13     pszStripLine = StripWhite(pszLineRead);
14     if(pszStripLine && *pszStripLine)
15         ADD_HISTORY(pszStripLine);
16
17     return pszStripLine;
18 }

StripWhite()函数沿用《GNU Readline库函数的应用示例》一文的实现。

结束命令行输入时,必须调用QuitCmdLine()函数退出输入。该函数会做一些必要的清理工作。

 1 /******************************************************************************
 2 * 函数名称:  QuitCmdLine
 3 * 功能说明:  命令行退出函数
 4 * 输入参数:  NA
 5 * 输出参数:  NA
 6 * 返回值  :  VOID
 7 * 注意事项:  结束命令行输入时必须调用该函数!
 8 ******************************************************************************/
 9 VOID QuitCmdLine(VOID)
10 {
11     CLR_LINE(pszLineRead);
12     pszLineRead = NULL;
13 }

3.3 Dsl_Test.c

Dsl_Test.c为DSL模块的测试函数,也是dsltst进程的入口所在。

该文件内仅有一个main()函数,实现如下:

 1 INT32S main(INT32S argc, CHAR *argv[])
 2 {
 3     INT32S retCode = 0;
 4     retCode = InitAppComm((DSL_DRV_APP>>4), 0);
 5     if(retCode != OSS_OK)
 6     {
 7         printf("Dsl Test[InitAppComm] failed, retCode=%d!\n", retCode);
 8         goto ErrorHandle;
 9     }
10
11     CHAR *pszCmdLine = "StartShell";
12     retCode = asend(DSL_DBG_SH_CMD, pszCmdLine, strlen(pszCmdLine)+1, DSL_DBG_PROC_PID);
13     if(retCode != OSS_OK)
14     {
15          printf("Dsl Test[asend](%s) failed, retCode=%d!\n", pszCmdLine, retCode);
16          goto ErrorHandle;
17     }
18
19     while(1)
20     {
21         pszCmdLine = ReadCmdLine("");
22         retCode = asend(DSL_DBG_SH_CMD, pszCmdLine, strlen(pszCmdLine)+1, DSL_DBG_PROC_PID);
23         if(retCode != OSS_OK)
24         {
25              printf("Dsl Test[asend](%s) failed, retCode=%d!\n", pszCmdLine, retCode);
26              goto ErrorHandle;
27         }
28         if(!strcmp(pszCmdLine, "-4"))
29         {
30             QuitCmdLine();
31             goto ErrorHandle;
32         }
33     }
34
35 ErrorHandle:
36     FreeAppComm();
37     return retCode;
38 }

其中,InitAppComm()函数初始化套接字通讯接口。asend()调用表示通过套接字发送DSL_DBG_SH_CMD异步消息到dsldbg线程(隶属DslDriver进程),消息体内容为终端命令行输入(pszCmdLine)。

为便于展示输入效果,将main()函数改为如下实现:

 1 INT32S main(INT32S argc, CHAR *argv[])
 2 {
 3     CHAR *pszCmdLine = NULL;
 4     while(1)
 5     {
 6         pszCmdLine = ReadCmdLine(">>");
 7         printf("pszCmdLine = %s!\n", pszCmdLine);
 8
 9         if(!strcmp(pszCmdLine, "-4"))
10         {
11             QuitCmdLine();
12             break;
13         }
14     }
15
16     printf("Quit!\n");
17     return 0;
18 }

编译后执行结果如下:

 1 [[email protected] ReadLine]$ ./Dsl_Test
 2 >>hello
 3 pszCmdLine = hello!
 4 >>world
 5 pszCmdLine = world!
 6 >>i‘m
 7 pszCmdLine = i‘m!
 8 >>clover!
 9 pszCmdLine = clover!!
10 >>-4
11 pszCmdLine = -4!
12 Quit!

3.4 Dsl_GetLine.c/h

Dsl_GetLine.c/h为DslDriver进程内读取终端命令行输入并缓存的实现。

根据前文所述的缓存机制,dsldbg线程接收到BcmShell启动命令行(“StartShell”)后,向dsldrv线程发送Shell启动消息,并缓存之后的命令行输入。dsldrv线程收到启动消息后调用dispatchingTask()函数“轮询”该缓存,若缓存非空则读取其中的命令行并做相应处理。

首先定义一组私有函数,如下:

 1 /******************************************************************************
 2 * 函数名称:  DslClearShCmd
 3 * 功能说明:  清除缓存的命令行输入
 4 ******************************************************************************/
 5 static VOID DslClearShCmd(VOID)
 6 {
 7     gIsShCmdCached = DSL_FALSE; //必须先设置有效标记后清除缓存
 8     memset(gCachedShCmd, 0, sizeof(gCachedShCmd));
 9 }
10
11 /******************************************************************************
12 * 函数名称:  DslReadShCmd
13 * 功能说明:  读取缓存的命令行输入
14 * 输入参数:  VOID
15 * 输出参数:  NA
16 * 返回值  :  成功: 已缓存的命令行输入;失败: NULL
17 ******************************************************************************/
18 static CHAR *DslReadShCmd(VOID)
19 {
20     if(!gIsShCmdCached)
21         return NULL;
22
23     gIsShCmdCached = DSL_FALSE;
24     return gCachedShCmd;
25 }

注意,清除或读取缓存时必须先设置gIsShCmdCached标记,以保证多线程环境下全局缓存的访问安全性(本线程读取时先向其他线程宣告该缓存已不可读)。

dsldbg线程接收到dsltst进程发来的消息后,调用DslDebugShCmd()函数解析和缓存命令行输入:

 1 /******************************************************************************
 2 * 函数名称:  DslDebugShCmd
 3 * 功能说明:  dsldbg线程接收命令行输入并处理
 4 * 输入参数:  VOID *lpMsg :线程当前消息内容指针
 5 * 输出参数:  NA
 6 * 返回值  :  VOID
 7 ******************************************************************************/
 8 VOID DslDebugShCmd(VOID *pvMsg)
 9 {
10     CHECK_SINGLE_POINTER(pvMsg, RET_VOID);
11     CHAR *pszShCmd = (CHAR *)pvMsg;
12
13     if(!strcmp(pszShCmd, "StartShell"))
14     {   //若为BcmShell启动命令(StartShell),则向dsldrv线程发送Shell启动消息
15         DslClearShCmd();
16         DslAsynSendDrv(DSL_SH_START_MSG, NULL, 0);
17         return;
18     }
19
20     memset(gCachedShCmd, 0, sizeof(gCachedShCmd));
21     strncpy(gCachedShCmd, pszShCmd, sizeof(gCachedShCmd)-1);
22     gCachedShCmd[sizeof(gCachedShCmd)-1] = ‘\0‘;
23     gIsShCmdCached = DSL_TRUE; //必须先缓存命令后设置有效标记
24 }

当终端输入异常终止时,如在多级提示符下直接输入-4导致dsltst提前退出,缓存内将没有命令可读。为避免dsldrv线程陷入死循环,需要增加超时自动退出轮询的机制。

超时机制相关的几个宏定义如下:

1 #define READ_LINE_TIMEOUT_MS      1000*120 //该超时时长内未等到命令行输入则启动退出机制
2 #define READ_LINE_STEP_MS         1000     //计时步长
3 #define READ_LINE_TRY_TIMES       (READ_LINE_TIMEOUT_MS/READ_LINE_STEP_MS)
4 #define READ_EXIT_TRY_TIMES       3        //该宏值不应小于BcmShell的提示符级数(如>、api>计两级)

基于该超时机制的命令行输入读取函数如下:

 1 /******************************************************************************
 2 * 函数名称:  DslGetLine
 3 * 功能说明:  dsldrv线程内BcmShell读取命令行输入
 4 * 输入参数:  CHAR *pszShCmd   :命令行缓冲区
 5 *           INT32U dwCmdSize :命令行缓冲区大小(字节)
 6 * 输出参数:  NA
 7 * 返回值  :  INT32U 命令行字符串长度
 8 ******************************************************************************/
 9 INT32U DslGetLine(CHAR *pszShCmd, INT32U dwCmdSize)
10 {
11     INT32U dwTryIdx = 0;
12     static INT32U dwExitTryCnt = 0;
13
14     for(; dwTryIdx < READ_LINE_TRY_TIMES; dwTryIdx++)
15     {
16         char *pszCmd = DslReadShCmd();
17         if(pszCmd != NULL)
18         {
19             dwExitTryCnt = 0;
20             strncpy(pszShCmd, pszCmd, dwCmdSize-1);
21             pszShCmd[dwCmdSize-1] = ‘\0‘;
22             return strlen(pszShCmd);
23         }
24         DslUsleep(READ_LINE_STEP_MS*1000);
25     }
26
27     //当与dsltst通讯异常时,此处可确保dispatchingTask函数安全退出
28     dwExitTryCnt++;
29     if(READ_EXIT_TRY_TIMES != dwExitTryCnt)
30         strcpy(pszShCmd, "exit");
31     else
32         strcpy(pszShCmd, "-4");
33     return strlen(pszShCmd);
34 }

3.5 其他

BCM厂家SDK相关头文件内对BCM_GETLINE宏定义如下:

1 #ifndef BCM_GETLINE
2     #define BCM_GETLINE  getLine
3     int getLine(char *s, int lim);
4 #endif

可见,在包含该头文件之前,重新定义BCM_GETLINE宏值为DslGetLine即可:

1 #define BCM_GETLINE  DslGetLine

四  效果验证

该缓存机制可精确模拟原SDK中BCM_GETLINE的同步等待特征。其操作示例如下:

 1 [email protected]:~ # dsltst
 2
 3 Enter line number to process (-1: all, -2: shutdown, -3: cli, -4: exit): -3
 4
 5 calling t&d module
 6 Entering interactive trace and debug session
 7 > api
 8
 9 api> configline downSlowMinDataRate 128
10  Configuration modified
11
12 api> exit
13 > ext
14 Unknown command: ext
15
16 > exitt(多输‘t‘后退格)
17 Try again from scratch, use ‘Delete‘ key to BackSpace!
18 Unknown command: exittgline downSlowMinDataRate 1
19
20 > exit
21
22 Enter line number to process (-1: all, -2: shutdown, -3: cli, -4: exit): -4
23 [email protected]:~ #
24 Now Quit the Dsl Shell!

dsltst命令不支持超时退出机制(需要另起线程),故操作结束后必须输入-4退出。

守护进程接收终端输入的一种变通性方法

时间: 2024-08-28 21:33:27

守护进程接收终端输入的一种变通性方法的相关文章

守护进程接收终端输入的一种变通性方法(二)

前言 本文作为<守护进程接收终端输入的一种变通性方法>的补充版,主要讨论不使用第三方库时,如何支持字符终端命令行的退格和历史记录.文中涉及的代码运行环境如下: 一  退格键 术语“退格”(BS,BackSpace)本意指删除光标左侧的一个字符.最初的打字机中,退格键将机架(carriage)回退一个位置:而在现代计算机系统中,退格键将显示器光标左移一个位置,并删除该处的字符,然后将该处之后的文字左移一个位置. 删除(DEL,Delete)键可追溯到计算机使用打孔磁带的年代.当时,纠正一个字符打

while持续输入的几种常用使用方法

while(scanf("%d,&n")!=EOF) 如果n被成功读入,则返回值为1, 如果n未被成功读入,则返回值为0, 如果遇到错误或遇到end of file,返回值为EOF. 那么什么时候返回EOF呢,简单来说在Windows下按住Ctrl+Z,在Mac下按住Ctrl+D,作为结束流的信号. 当然你有一些特殊的要求,比如我想让n=0时结束. while(scanf("%d",&n)!=EOF) { if(n==0) break; } 当然我将

从进程组、会话、终端的概念深入理解守护进程

一.写在前面 「守护进程」是 Linux 的一种长期运行的后台服务进程,也有人称它为「精灵进程」.我们常见的 httpd.named.sshd 等服务都是以守护进程 Daemon 方式运行的,通常服务名称以字母d结尾,也就是 Daemon 第一个字母.与普通进程相比它大概有如下特点: 无需控制终端(不需要与用户交互) 在后台运行 生命周期比较长,一般是随系统启动和关闭 二.守护进程必要性 为什么要设置为守护进程,普通进程不可以吗? 当我们在命令行提示符后输入类似./helloworld程序时,在

守护进程 python

守护进程(类似Windows的服务):通常被定义为一个后台进程,而且它不属于任何一个终端会话(terminal session).许多系统服务由守护程序实施:如网络服务,打印等. 下面介绍下守护进程的基本编码过程以及python的对应实现: 1. 调用 fork 并使父进程退出(exit)( 若父进程退出,子进程尚未结束,则子进程会被init进程领养,也就是说init进程将成为该子进程的父进程).这一步骤的目的在于.首先,如果守护进程是通过一个简单的shell命令建立的,那么在父进程终止的时候s

ASP.ENT Core Linux 下 为 donet创建守护进程(转载)

原文地址:http://www.cnblogs.com/savorboard/p/dotnetcore-supervisor.html 前言 在上篇文章中介绍了如何在 Docker 容器中部署我们的 asp.net core 应用程序,本篇主要是怎么样为我们在 Linux 或者 macOs 中部署的 dotnet 程序创建一个守护进程,来保证我们的程序在异常或者是电脑重启的时候仍然能够正常访问. 如果你以后用准备使用 asp.net core来开发项目的话,程序并且部署到 Linux 上的话,那

《Unix环境高级编程》读书笔记 第13章-守护进程

1. 引言 守护进程是生存期长的一种进程.它们常常在系统引导装入时启动,仅在系统关闭时才终止.它们没有控制终端,在后台运行. 本章说明守护进程结构.如何编写守护进程程序.守护进程如何报告出错情况. 2. 守护进程的特征 基于BSD的系统下执行:ps -axj -a 显示由其他用户所拥有的进程的状态:-x 显示没有控制终端的进程状态:-j 显示与作业有关的信息 基于System V的系统下执行:ps -efj Linux下执行以上两个命令输出一致 常见的守护进程: kswapd,内存换页守护进程.

守护进程详细总结

1. 守护进程的概念: 守护进程(Daemon)是一种运行在后台的一种特殊的进程,它独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件.由于在Linux中,每个系统与用户进行交流的界面成为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端被称为这些进程的控制终端,当控制终端被关闭的时候,相应的进程都会自动关闭.但是守护进程却能突破这种限制,它脱离于终端并且在后台运行,并且它脱离终端的目的是为了避免进程在运行的过程中的信息在任何终端中显示并且进程也不会被任何终端所产生的终端

守护线程、守护进程

1. 几点认识: java中有两类线程:user thread(用户线程),daemon thread(守护线程) 守护线程为其他线程的运行提供服务,例如GC线程(垃圾回收线程),内存管理线程. 虚拟机判断程序执行结束的标准时不考虑守护线程:如果user thread全部撤离,daemon thread因为无服务对象,所以虚拟机也就退出了. public final void setDaemon(boolean on) :用户自行设定守护线程 是JVM模拟了操作系统中的“守护进程”而定义出的一种

守护进程详解及创建,daemon()使用

一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.它不需要用户输入就能运行而 且提供某种服务,不是对整个系统就是对某个用户程序提供服务.Linux系统的大多数服务器就是通过守护进程实现的.常见的守护进程包括系统日志进程 syslogd. web服务器httpd.邮件服务器sendmail和数据库服务器mysqld等. 守护进程一般在系统启动时开始运行,除非强行终止,否则直到系统关机都保持运行.守护进