守护线程、守护进程

1. 几点认识:

  1. java中有两类线程:user thread(用户线程),daemon thread(守护线程)
  2. 守护线程为其他线程的运行提供服务,例如GC线程(垃圾回收线程),内存管理线程。
  3. 虚拟机判断程序执行结束的标准时不考虑守护线程:如果user thread全部撤离,daemon thread因为无服务对象,所以虚拟机也就退出了。
  4. public final void setDaemon(boolean on) :用户自行设定守护线程
  5. 是JVM模拟了操作系统中的“守护进程”而定义出的一种机制。但与守护进程有所不同
    1. 不能将正在运行的线程设置为守护线程:thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。(守护进程是创建后,让其脱离会话+进程组+控制终端控制)
    2. 在Daemon中创建的线程也是守护线程。(守护进程fork()出的进程不是守护进程,因为其父进程不再是init进程)
    3. 不是所有的应用都可以分配给守护线程来服务。比如读写操作或计算逻辑,因为在daemon还没操作时,虚拟机已经退出了。

  例子:

public class DaemonThreadTest {
    public static void main(String[] args){
        Thread t1 = new MyThread();
        Thread t2 = new Thread( new MyDaemon() );
        t2.setDaemon(true);
        t1.start();
        t2.start();
    }
}

class MyDaemon implements Runnable{
    public void run(){
        for( long i=0; i<9999999L; i++ )
            System.out.println("后台线程第" + i + "次执行!");
        try{
            Thread.sleep(7);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
    }
}

class MyThread extends Thread{
    public void run(){
        for( int i=0; i<5; i++ )
            System.out.println("线程第" + i + "次执行!");
        try{
            Thread.sleep( 7 );
        }catch( InterruptedException e ){
            e.printStackTrace();
        }
    }
}

输出:

后台线程第0次执行!
线程第0次执行!
后台线程第1次执行!
线程第1次执行!
后台线程第2次执行!
线程第2次执行!
后台线程第3次执行!
线程第3次执行!
后台线程第4次执行!
...
后台线程第339次执行!

即前台线程保证执行完毕,后台线程不一定。

2. 守护进程

  1. 定义:Linux或Unix操作系统中,在系统引导时会开启很多服务,这些服务就是守护进程,即后台服务进程。例如amd(自动安装NFS守候进程)、Lpd(打印服务器)等。
  2. 生存期长。通常在系统引导装入是启动,在系统关闭时终止。
  3. 独立于控制终端并且周期性地执行某种任务。从而其在执行过程中的信息不会在终端显示,并且也不会终端进程信息所打断。
    • 终端:Linux中,每个系统与用户交流的界面称为终端(terminal),每个从此终端开始运行的进程都会依附于此终端,该终端就称为这些进程的控制终端。
    • 当控制终端被关闭时,相应的用户进程都会自动关闭。而守护进程能突破这种限制,即它在系统关闭使才会终止。
  4. 什么时候使用守护进程?
    • 如果不想让某个进程因为用户/终端/其他变化而受到影响,则将该进程设为守护进程。
  5. 创建过程:
    1. 创建子进程,父进程退出。

      • 即创建子进程后,显示退出父进程,造成在终端这一进程已运行完毕的假象。之后的操作都由子进程完成。形式上做到与控制终端脱离。
      • 孤儿进程:父进程先于子进程退出,则称为孤儿进程。系统发现一个孤儿进程后,就自动有1号进程(init进程)收养,即该子进程称为init进程的子进程。
    2. 在子进程中创建新会话。
      • 继承:调用fork()函数,子进程会拷贝父进程的所有会话期、进程组、控制终端等。需要重设这些,才使子进程真正的与控制终端脱离
      • 进程组:一个或多个进程集合。每个进程有进程pid,进程组有组ID。pid和进程组ID都是一个进程的必备属性。每个进程组都有组长进程,其进程号等于进程组ID。当进程组ID不受组长进程退出的影响。
      • 会话期:一个或多个进程组集合。通常,一个会话始于用户登录,终于用户退出,这之间的所有进程都属于该会话期。
      • setsid:创建新会话,并担任该会话组组长。有3个作用:
        • 让进程摆脱原会话的控制
        • 让进程摆脱原会话组的控制
        • 让进程摆脱原控制终端的控制
    3. 改变当前目录为根目录
      • 继承:fork()创建的子进程还拷贝了父进程的当前工作目录。需要重设。
      • 进程运行中,当前目录所在文件系统是不能卸载的,即原工作目录无法卸载。可能造成很多麻烦,如需要进入单用户模式。所以必须重设当前目录。
      • chdir("/"):重设为根目录
    4. 重设文件权限掩码
      • 文件权限掩码:屏蔽掉文件权限中的对应位。有个文件权限掩码是050,它就屏蔽了文件组拥有者的可读与可执行权限。
      • 继承:fork()创建的子进程还继承了父进程的文件权限掩码。
      • umask(0):重设为0,灵活性更强。
    5. 关闭文件描述符
      • 继承:fork()创建的子进程从父进程继承了一些已经打开了的文件。被打开的进程可能永远不会被守护进程使用,却消耗资源。所以必须手动关闭文件描述符为0、1和2 的3个文件(常说的输入、输出和报错)。
    6. 守护进程退出处理
      • 可能需要支持用户在外部手动停止守护进程运行,通常使用kill命令。编码实现kill发出的signal信号处理,达到线程正常退出。
signal(SIGTERM, sigterm_handler);
void sigterm_handler(int arg)
{
_running = 0;
}

  创建守护进程的一个实例:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#define MAXFILE 65535
void sigterm_handler(int arg);
volatile sig_atomic_t _running = 1;
int main()
{
pid_t pc,pid;
int i,fd,len,flag = 1;
char *buf="this is a Dameon\n";
len = strlen(buf);
pc = fork(); //第一步
if(pc<0){
printf("error fork\n");
exit(1);
}
else if(pc>0)
exit(0);
pid = setsid(); //第二步[1]
if (pid < 0)
perror("setsid error");
chdir("/"); //第三步
umask(0); //第四步
for(i=0;i<MAXFILE;i++) //第五步
close(i);
signal(SIGTERM, sigterm_handler);
while( _running )
{
if( flag ==1 &&(fd=open("/tmp/daemon.log",O_CREAT|O_WRONLY|O_APPEND,0600))<0)
{
perror("open");
flag=0;
exit(1);
}
write(fd,buf,len);
close(fd);
usleep(10*1000); //10毫秒
}
}
void sigterm_handler(int arg)
{
_running = 0;
}

createDeamon

时间: 2024-11-08 05:39:42

守护线程、守护进程的相关文章

死锁现象与解决方案,开启线程的2种方式,守护线程,线程VS进程,线程互斥锁,信号量

死锁现象与解决方案 from threading import Thread,Lock,active_count import time mutexA=Lock() # 锁1 mutexB=Lock() # 锁2 class Mythread(Thread): def run(self): self.f1() self.f2() def f1(self): mutexA.acquire() print('%s 拿到A锁' %self.name) mutexB.acquire() print('%

进程间的数据共享、进程池的回调函数和线程初识、守护线程

一.进程的数据共享 进程间数据是独立的,可以借助于队列或管道实现通信,二者都是基于消息传递的 虽然进程间数据独立,但可以通过Manager实现数据共享. 把所有实现了数据共享的比较便捷的类都重新又封装了一遍,并且在原有的multiprocessing基础上增加了新的机制 list dict等 数据共享的机制 支持数据类型非常有限 list dict都不是数据安全的,你需要自己加锁来保证数据安全 Manager用法: Manager().dict() # 创建共享的字典 Manager().lis

线程的创建 验证线程之间共享数据 守护线程 线程进程效率对比 锁 死锁 递归锁

线程(from threading import Thread):CPU调度的最小单位 线程的两种创建方式:方式一: 1 from threading import Thread 2 def f1(i): 3 print(i) 4 if __name__ == '__main__': 5 for i in range(10): 6 t = Thread(target=f1,args=(i,)) 7 t.start() 8 print('主线程') 方式二: 1 from threading im

关于守护进程和守护线程的区别

一.守护进程 1.1.什么是守护进程? 1.守护进程会在主进程代码运行结束的情况下,立即挂掉. 2.守护进程本身就是一个子进程. 3.主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束, 1.2.为什么要用守护进程? 1.守护进程本身就是一个子进程,所以在主进程需要将任务并发执行的时候需要开启子进程. 2.当该子进程执行的任务生命周期伴随着主进程的生命周期时,就需要将该子进程做成守护进程.

python开发线程:线程&amp;守护线程&amp;全局解释器锁

一 threading模块介绍 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍 官网链接:https://docs.python.org/3/library/threading.html?highlight=threading# 二 开启线程的两种方式 #方式一 from threading import Thread import time def sayhi(name): time.sleep(2) print('%s

Java中的守护线程和非守护线程(转载)

<什么是守护线程,什么是非守护线程> Java有两种Thread:“守护线程Daemon”(守护线程)与“用户线程User”(非守护线程). 用户线程:非守护线程包括常规的用户线程或诸如用于处理GUI事件的事件调度线程,Java虚拟机在它所有非守护线程已经离开后自动离开. 守护线程:守护线程则是用来服务用户线程的,比如说GC线程.如果没有其他用户线程在运行,那么就没有可服务对象,也就没有理由继续下去.(操作系统里面是没有所谓的守护线程的概念,只有守护进程一说,但是Java语言机制是构建在JVM

python全栈开发基础【第二十四篇】(利用threading模块开线程、join与守护线程、GIL与Lock)

一多线程的概念介绍 threading模块介绍 threading模块和multiprocessing模块在使用层面,有很大的相似性. 二.开启多线程的两种方式 创建线程的开销比创建进程的开销小,因而创建线程的速度快. #开启进程的第一种方式 from multiprocessing import Process from threading import Thread import os import time def work(): print('<%s> is running'%os.g

9 并发编程-(线程)-守护线程&amp;互斥锁

一 .守护线程 无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁 需要强调的是:运行完毕并非终止运行 1.对主进程来说,运行完毕指的是主进程代码运行完毕 2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕 详细解释: 1.主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收), 然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束, 2.主线程在其他非守护线程运行完毕后才算运行完毕

python网络编程--线程(锁,GIL锁,守护线程)

1.线程 1.进程与线程 进程有很多优点,它提供了多道编程,让我们感觉我们每个人都拥有自己的CPU和其他资源,可以提高计算机的利用率.很多人就不理解了,既然进程这么优秀,为什么还要线程呢?其实,仔细观察就会发现进程还是有很多缺陷的,主要体现在两点上: 进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了. 进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行. 如果这两个缺点理解比较困难的话,举个现实的例子也许你就清楚

并发编程(四)--线程、开启线程、守护线程、线程互斥锁

一.什么是线程 进程其实一个资源单位,而进程内的线程才是cpu上的执行单位,线程其实指的就是代码的执行过程 二.进程和线程的区别 1. 同一进程下的多个线程共享该进程内的资源2. 创建线程的开销要远远小于进程 三.利用Thread类开启线程的两种方式 1.Thread类 Thread实例对象的方法 # isAlive(): 返回线程是否活动的. # getName(): 返回线程名. # setName(): 设置线程名. threading模块提供的一些方法: # threading.curr