PS:要转载请注明出处,本人版权所有。

PS: 这个只是基于《我自己》的理解,

如果和你的原则及想法相冲突,请谅解,勿喷。

前置说明

  本文作为本人csdn blog的主站的备份。(BlogID=044)

  本文发布于 2017-11-17 16:33:04,现用MarkDown+图床做备份更新。blog原图已丢失,使用csdn所存的图进行更新。(BlogID=044)

环境说明

  无

前言


  无

Linux Daemo 和 单例模式


Linux 单例模式

  原理:创建一个保存进程名的文件,利用linux的文件锁来判断文件是否加锁来判断是否已有相同的程序运行。

例子

int CheckIsSingleton(int *fd)
{ struct flock loglock;
char nowpid[10];
int num; if (0 > (*fd = open(LOCK_FILE_NAME, O_WRONLY | O_CREAT, 0600)))
{ perror("open lock file failed!");
return -1;
}
/* struct flock {
...
short l_type; // Type of lock: F_RDLCK,
//F_WRLCK, F_UNLCK
short l_whence; // How to interpret l_start:
//SEEK_SET, SEEK_CUR, SEEK_END
off_t l_start; // Starting offset for lock
off_t l_len; // Number of bytes to lock
pid_t l_pid; // PID of process blocking our lock
// (set by F_GETLK and F_OFD_GETLK)
...
}; As well as being removed by an explicit F_UNLCK, record locks are auto‐
matically released when the process terminates. */
memset(&loglock, 0, sizeof(struct flock));
loglock.l_type = F_WRLCK;
loglock.l_whence = SEEK_SET;
if ( 0 > fcntl(*fd, F_GETLK, &loglock) ){//检查是否能够加F_WRLCK锁,不能够确认文件是否有锁。 close(*fd);
perror("fcntl F_WRLCK failed");
_exit(-1);
}
else{ if ( loglock.l_type != F_UNLCK){ close(*fd);
write(2,"check F_WRLCK failed\n",sizeof("check F_WRLCK failed\n"));//stdout was closed!!!
write(2,"The same process is running\n",sizeof("The same process is running\n"));
_exit(-1);
}
}
loglock.l_type = F_WRLCK;
loglock.l_start = 0; //从文件开始加锁
loglock.l_whence = SEEK_SET;
loglock.l_len = 0; //加锁整个文件
if ( 0 > fcntl(*fd, F_SETLK, &loglock) ){ close(*fd);
perror("fcntl F_WRLCK failed");
printf("The same process is running\n");
_exit(-1);
} num = sprintf(nowpid, "%d",getpid());
write(*fd, nowpid, num);
return 0;
}
Daemon 简单设计

  原理

  1. 利用fork来实现。setsid使当前子进程成为新的进程组长,在使用fork使其与终端脱离,设置工作目录,设置文件掩码
  2. 利用系统提供的daemon()(此调用来至于glibc)来完成功能。(底层使用fork来实现)

      例子
void CreateDaemonProcess_daemon()//根据daemon函数的源码来看,后面补充了一个fork比较安全
{
/*
The daemon() function is for programs wishing to detach themselves from
the controlling terminal and run in the background as system daemons. If nochdir is zero, daemon() changes the process's current working
directory to the root directory ("/"); otherwise, the current working
directory is left unchanged. If noclose is zero, daemon() redirects standard input, standard output
and standard error to /dev/null; otherwise, no changes are made to
these file descriptors. int
daemon(nochdir, noclose)
int nochdir, noclose;
{
int fd; switch (__fork()) {
case -1:
return (-1);
case 0:
break;
default:
_exit(0);
} if (__setsid() == -1)
return (-1); if (!nochdir)
(void)__chdir("/"); if (!noclose) {
struct stat64 st; if ((fd = open_not_cancel(_PATH_DEVNULL, O_RDWR, 0)) != -1
&& (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0)
== 0)) {
if (__builtin_expect (S_ISCHR (st.st_mode), 1) != 0
#if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
&& (st.st_rdev
== makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR))
#endif
) {
(void)__dup2(fd, STDIN_FILENO);
(void)__dup2(fd, STDOUT_FILENO);
(void)__dup2(fd, STDERR_FILENO);
if (fd > 2)
(void)__close (fd);
} else {
// We must set an errno value since no
// function call actually failed.
close_not_cancel_no_status (fd);
__set_errno (ENODEV);
return -1;
}
} else {
close_not_cancel_no_status (fd);
return -1;
}
}
return (0);
} */
if (0 > daemon(0, 0))
{ perror("daemon call failed!");
_exit(-1);
}
//setsid();
// int fd;
// if ( 0 > (fd = open("/dev/tty", O_RDWR )) ){ // perror("open tty failed!");
// _exit(-1);
// } // if ( ioctl(fd, TIOCNOTTY, NULL) < 0){ // perror("ioctl TIOCNOTTY failed!");
// close(fd);
// _exit(-1);
// }
// close(fd); int pid;
pid = fork();
if (pid == -1)
{ perror("fork first error!");
}
else if (pid > 0)
{ //parent 1 _exit(1);
}
else
{ //child pid==0
}
return;
} void CreateDaemonProcess_Fork()
{ pid_t pid, pid1, pid2; pid = fork(); if (pid == -1)
{ perror("fork first error!");
}
else if (pid > 0)
{ //parent 1 _exit(1);
}
else
{ //child pid==0 if (0 > (pid1 = setsid()))
{
perror("setsid() call failed!");
_exit(-1); //
}
else
{
printf("New session id is %d\n", pid1);
} pid2 = fork(); if (pid2 == -1)
{ perror("fork second error!");
}
else if (pid2 > 0)
{ //parent _exit(1);
}
else
{
chdir("/"); //change current working directory
umask(0);
return;
}
}
}

  说明:

  1. 双fork的原因是进程组长会开启终端。而我们的daemon程序是不需要终端的。
  2. 文件掩码用于设置默认的文件权限。
  3. 子进程会继承父进程的大部分属性,包括已打开文件描述符、文件掩码、工作目录等待,这些根据需求处理。

后记


  无

参考文献


打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)

PS: 请尊重原创,不喜勿喷。

PS: 要转载请注明出处,本人版权所有。

PS: 有问题请留言,看到后我会第一时间回复。

Linux Daemon & 单例模式 设计与实现的更多相关文章

  1. 设计模式之PHP项目应用——单例模式设计Memcache和Redis操作类

    1 单例模式简单介绍 单例模式是一种经常使用的软件设计模式. 在它的核心结构中仅仅包括一个被称为单例类的特殊类. 通过单例模式能够保证系统中一个类仅仅有一个实例并且该实例易于外界訪问.从而方便对实例个 ...

  2. 利用单例模式设计数据库连接Model类

    之前在<[php]利用php的构造函数与析构函数编写Mysql数据库查询类>(点击打开链接)写过的Mysql数据库查询类还不够完美,利用<[Java]单例模式>(点击打开链接) ...

  3. python学习(28) 浅谈可变对象的单例模式设计

    python开发,有时候需要设计单例模式保证操作的唯一性和安全性.理论上python语言底层实现和C/C++不同,python采取的是引用模式,当一个对象是可变对象,对其修改不会更改引用的指向,当一个 ...

  4. [转] Linux Daemon Writing HOWTO

    Linux Daemon Writing HOWTO Devin Watson v1.0, May 2004 This document shows how to write a daemon in ...

  5. [转载] Linux Futex的设计与实现

    Linux Futex的设计与实现 引子 在编译2.6内核的时候,你会在编译选项中看到[*] Enable futex support这一项,上网查,有的资料会告诉你"不选这个内核不一定能正 ...

  6. 创建 SysV 风格的 linux daemon 程序

    本文介绍如何使用 C 语言创建 Linux 系统中 SysV 风格的 daemon 程序.注意:这是一种旧式的 daemon 程序写法,进入 systemd 时代后是不需要通过这样的方式创建 daem ...

  7. .NET跨平台实践:.NetCore、.Net5/6 Linux守护进程设计

    之前,我写过两篇关于用C#开发Linux守护进程的技术文章,分别是<.NET跨平台实践:用C#开发Linux守护进程>和<.NET跨平台实践:再谈用C#开发Linux守护进程 - 完 ...

  8. Linux UBI子系统设计初探

    问题领域 flash存储设备存在如下特点: 存在坏块 使用寿命较短 存储介质不稳定 读写速度慢 不支持随机访问(nand) 只能通过擦除将0改成1 最小读写单位为page or sub-page 便宜 ...

  9. Linux Daemon 类程序

    1.后台daemon程序(精灵程序) 在Linux中专门提供了一个函数来完成这个daemon化的过程,这个函数的原型如下 int daemon (int __nochdir, int __noclos ...

  10. python to be linux daemon

    所需第三方库:python-daemon[https://pypi.python.org/pypi/python-daemon/] 使用方式: python linux_service.py star ...

随机推荐

  1. Java并发(十)----线程之守护线程

    默认情况下,Java 进程需要等待所有线程都运行结束,才会结束.有一种特殊的线程叫做守护线程,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束. 例: log.debug(&q ...

  2. 资深工程师 VSCode C/C++ 必备开发插件

    1.前言 俗话说"工欲善其事,必先利其器",下面介绍几个VSCode提高开发效率的插件,资深工程师必备. 2.基础插件 2.1.Chinese(Simplified) vscode ...

  3. 函数防抖与节流 - js

    防抖(debounce)和节流(throttle)是在 高频次调用函数 的场景下,常用的解决方案了.故名思意,可以节省开销,优化体验. 二者的区别: 防抖: 我们让想要执行的函数只在最后一次调用完一小 ...

  4. react 快速接入 sentry,性能监控与错误上报踩坑日记

    壹 ❀ 引 本文是我入职第一个月所写,在主导基建组的这段时间也难免会与错误监控和性能监控打交道,因为公司主要考虑接入sentry,所以对于接入sentry的基建任务也提了一些需求,主要分为: 支持查看 ...

  5. NC16810 [NOIP1999]拦截导弹

    题目链接 题目 题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达 ...

  6. .NET周刊【2月第2期 2024-02-11】

    国内文章 C#/.NET该如何自学入门? https://www.cnblogs.com/Can-daydayup/p/18006914 随着DotNetGuide技术社区交流群的扩大,很多新成员希望 ...

  7. Maven多模块项目版本统一管理

    如图所示,项目中定义了这样几个模块: pdd-workflow-build :定义项目版本,及全局配置 pdd-workflow-dependencies :外部依赖管理,统一管理所有用到的外部依赖的 ...

  8. TS内置类型与拓展

    TS内置类型与拓展 TypeScript具有类型系统,且是JavaScript的超集,其可以编译成普通的JavaScript代码,也就是说,其是带有类型检查的JavaScript. 内置类型 Type ...

  9. win32-封装BeginPaint

    Graphics* StartPaint(HWND win, HDC* hdc, PAINTSTRUCT* ps) { *hdc = BeginPaint(win, ps); return new G ...

  10. Docker进阶之01-Docker Compose编排工具

    Docker Compose是什么 https://github.com/docker/compose 可以按项目为单位管理多个Docker容器,Python语言开发,底层调用Docker的API接口 ...