Python threading setDaemon 强制退出线程

setDaemon

th.setDaemon(True)   默认参数为 False

setDaemon(True)将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起。当没有存活的非守护进程时,整个python程序才会退出。

总结:

     如果主线程执行完以后,还有其他非守护线程,主线程是不会退出的,会被无限挂起;必须将线程声明为守护线程之后,如果队列中的数据运行完了,那么整个程序想什么时候退出就退出,不用等待。

 代码示例:

# -*- coding:utf-8 -*-
# @Time    : 2021/1/6 10:07
# @Author  : hllyzms
import ctypes
import inspect
import threading
import time
from threading import Thread


class SingletonData(object):
    _instance_lock = threading.Lock()

    def __new__(cls, *args, **kwargs):
        if not hasattr(SingletonData, "_instance"):
            with SingletonData._instance_lock:
                if not hasattr(SingletonData, "_instance"):
                    SingletonData._instance = object.__new__(cls)
                    ins = SingletonData._instance
                    return ins

        return SingletonData._instance

    def __init__(self, info_dict=dict()):
        self.mainth = False
        self.childth = False

singleton = SingletonData()

class DemoThread(Thread):

    def run(self):
        if singleton.mainth:
            return
        singleton.mainth = True
        for i in range(1,5):
            print("DemoThread:",i)
            singleton.childth = i
            if hasattr(singleton, "th"):
                th = getattr(singleton, "th")
                if th.is_alive():
                    stop_thread(th)

            singleton.th = Thread(target=thdemo,args=(i,))
            singleton.th.start()
            count = 0
            while True:
                if count ==5:
                    print("DemoThread 退出")
                    return
                count += 1
                if not singleton.mainth:
                    print("DemoThread退出 close")
                    return
                if singleton.childth == i:
                    time.sleep(1)
                else:
                    break
        singleton.mainth = False



def thdemo(i):
    num = 1
    while singleton.childth == i:
        print("child",i,num)
        num += 1
        # if num > 4:
        #     break
        time.sleep(1)



def _async_raise(tid, exctype):
    # todo 强制退出线程  忽略掉报错
    try:
       """raises the exception, performs cleanup if needed"""
       tid = ctypes.c_long(tid)
       if not inspect.isclass(exctype):
          exctype = type(exctype)
       res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
       if res == 0:
          raise ValueError("invalid thread id")
       elif res != 1:
          # """if it returns a number greater than one, you're in trouble,
          # and you should call it again with exc=NULL to revert the effect"""
          ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
          raise SystemError("PyThreadState_SetAsyncExc failed")
    except:
        pass


def stop_thread(thread):
   _async_raise(thread.ident, SystemExit)

if __name__ == '__main__':
    th = DemoThread()
    th.setDaemon(True)
    th.start()
    th.join()
    time.sleep(3)

运行结果:

DemoThread: 1
child 1 1
child 1 2
child 1 3
child 1 4
child 1 5
child 1 6
DemoThread 退出
child 1 7
child 1 8
child 1 9

但是如果在一个web项目中启动DemoThread,在 DemoThread退出的时候 thdemo 没有退出

因为web项目的主进程没有退出,上面的示例能退出(也不是应为DemoThread退出)time.sleep(3)之后主进程退出了

我在我的django项目中写了一个小测试 使用 stop_thread 可以退出线程


class DemothViewSet(mixins.ListModelMixin,mixins.CreateModelMixin,mixins.UpdateModelMixin,viewsets.GenericViewSet,mixins.DestroyModelMixin):


    serializer_class = DemothSerializer

    def list(self, request, *args, **kwargs):
        # 获取当前状态
        from utils.demoth import singleton
        if hasattr(singleton, "demoth"):
            demoth = getattr(singleton, "demoth")
            mainstatus = demoth.is_alive()
        else:
            mainstatus = False

        if hasattr(singleton, "th"):
            th = getattr(singleton, "th")
            childstatus = th.is_alive()
        else:
            childstatus = False
        return Response({"main":singleton.mainth,"child":singleton.childth,"mainstatus":mainstatus,"childstatus":childstatus})

    def create(self, request, *args, **kwargs):
        # todo 用于开启关闭线程
        from utils.demoth import singleton
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        close = serializer.validated_data.get("close")
        if close:
            if hasattr(singleton,"demoth"):
                demoth = getattr(singleton, "demoth")
                mainstatus = demoth.is_alive()
                print("mainstatus", mainstatus)
                if mainstatus:
                    # todo 线程还在活着 手动杀掉
                    stop_thread(demoth)
            else:
                mainstatus = False
            if hasattr(singleton, "th"):
                demoth = getattr(singleton, "th")
                childstatus = demoth.is_alive()
                if childstatus:
                    # todo 线程还在活着 手动杀掉
                    stop_thread(demoth)
            else:
                childstatus = False

        else:
            
            demoth = DemoThread()
            demoth.setDaemon(True)
            demoth.start()
            singleton.demoth = demoth
            mainstatus = singleton.demoth.is_alive()
            print("mainstatus",mainstatus)
            childstatus = "Unknown"
        data = serializer.data
        data.update({"mainstatus":mainstatus,"childstatus":childstatus})
        return Response(data, status=status.HTTP_201_CREATED,)


    def update(self, request, *args, **kwargs):
        # todo 用于设置DemoThread 线程 退出
        from utils.demoth import singleton
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        mainth = serializer.validated_data.get("mainth")
        singleton.mainth = mainth
     
        if hasattr(singleton, "demoth"):
            demoth = getattr(singleton, "demoth")
            mainstatus = demoth.is_alive()
        else:
            mainstatus = False

        if hasattr(singleton, "th"):
            th = getattr(singleton, "th")
            childstatus = th.is_alive()
        else:
            childstatus = False
        return Response({"mainth":mainth,"mainstatus":mainstatus,"childstatus":childstatus})

    def destroy(self, request, *args, **kwargs):
        # todo 用于退出子线程
        from utils.demoth import singleton
        singleton.childth = 0
        return Response({"childth":0})

猜你喜欢

转载自blog.csdn.net/weixin_37989267/article/details/112283372