There is a pattern that the program did not stop when using Python threading

Program "I can't stop ..." I "Please stop"

This article is the 7th day article of N High School Advent Calendar 2019. I am currently in my second year of second grade (there were many things when I transferred) and am attending a school course. N High is very grateful that I can do my own project in programming time as long as I finish the essential tasks.

In this article, I'll write about the problems I faced while making Discord and Twitter bots in Python. Please point out any mistakes.

Overview

When I tried to stop a program using Python threading with Keyboard Interrupt (Ctrl + C), it didn't stop at once for some reason. Upon further investigation, sys.exit () did not stop.

environment

OS: Windows 10 Home Runtime: Python 3.8.0

Practice

For the time being, I decided to write code using threading for verification.

import threading
import time

#Function definition
def a():
    for i in range(5):
        time.sleep(1)
        print("A" + str(i))

def b():
    time.sleep(0.5)
    for j in range(5):
        time.sleep(1)
        print("B" + str(j))

#Thread object creation
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)

#Run
t1.start()
t2.start()

#Wait until the end
t1.join()
t2.join()

print("Finish")

As expected, the output looks like this: Finish was displayed at the same time as B4 was displayed.

A0
B0
A1
B1
A2
B2
A3
B3
A4
B4
Finish

Now, let's remodel this into an infinite loop.

import threading
import time

#Function definition
def a():
    c=1
    while True:
        time.sleep(1)
        print("A" + str(c))
        c+=1

def b():
    k=1
    time.sleep(0.5)
    while True:
        time.sleep(1)
        print("B" + str(k))
        k+=1

#Thread object creation
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)

#Run
t1.start()
t2.start()

#Wait until the end
t1.join()
t2.join()

The output is as follows.

A1
B1
A2
B2
A3
B3
^CTraceback (most recent call last):
  File "***********.py", line 28, in <module>
    t1.join()
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 1011, in join
    self._wait_for_tstate_lock()
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 1027, in _wait_for_tstate_lock
    elif lock.acquire(block, timeout):
KeyboardInterrupt
A4
B4
A5
B5
A6
B6
^CException ignored in: <module 'threading' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py'>
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 1388, in _shutdown
    lock.acquire()
KeyboardInterrupt: 

For some reason it didn't stop at the first Keyboard Interrupt. This time I did it twice and it stopped, but I want to avoid it if possible.

solution?

You don't have to "wait until the end". In other words, just delete **. Join (). When I actually delete t1.join () and t2.join () and execute it, it becomes like this.

A1
B1
A2
B2
^CException ignored in: <module 'threading' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py'>
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 1388, in _shutdown
    lock.acquire()
KeyboardInterrupt:

There was a time when I was thinking, "If it's a process that uses While True, it won't end in the middle, and if you stop with Ctrl + C, yeah." But there are surprising scenes that I want to stop. For example, when you want to shut down a bot with a command. The following contents were discovered at that time.

sys.exit () doesn't work either

import threading
import time
import sys

#Function definition
def a():
    c=1
    while True:
        time.sleep(1)
        print("A" + str(c))
        c+=1

def b():
    k=1
    time.sleep(0.5)
    while True:
        time.sleep(1)
        print("B" + str(k))
        k+=1

#Thread object creation
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)

#Run
t1.start()
t2.start()

#forced termination
print("Terminate")
sys.exit()
print("Terminated")

The expected output is a Terminate line. This is because the program should not be executed after sys.exit () (this is strictly wrong, as described later). However, when this is actually operated, the following output is obtained.

Terminate
A1
B1
A2
B2
A3
B3
A4
B4

sys.exit () runs after Terminate, and Terminated is hidden, but the above two functions have been executed normally.

Cause

There was a mistake in recognizing sys.exit (). It doesn't stop the whole program, it stops the thread. The only thread that stops in the above program is the thread that is executing print ("Terminate "), and sys.exit () has not arrived at the two threads that are in an infinite loop. One way to stop it is to run sys.exit () inside the thread object. But what I want to do is "stop all threads at once".

solution

Daemon threads other than the main thread.

import threading
import time
import sys

#Function definition
def a():
    c=1
    while True:
        time.sleep(1)
        print("A" + str(c))
        c+=1

def b():
    k=1
    time.sleep(0.5)
    while True:
        time.sleep(1)
        print("B" + str(k))
        k+=1

def c():
    while True:
        n = input()
        if n == "e":
            print("Terminate")
            sys.exit()

#Thread object creation
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)

#Daemonization
t1.setDaemon(True)
t2.setDaemon(True)

#Run
t1.start()
t2.start()
c() # c()Only run on the main thread

Changed to run sys.exit () when receiving input ʻe`. The output result is as follows.

A1
B1
A2
e
Terminate

If you press e and press Enter (Return), execution will stop there. The daemon thread behaves as ** automatically disappearing when a thread other than the daemon thread is not running **. If there is only one process that includes sys.exit (), it may be better to run it on the main thread, that is, on the outermost side without doing threading.Thread ().

Summary

To be honest, I tried to find out the cause, but I don't know. Somehow the signal was something like that, but I can't write it correctly with my own skill, so I won't post it. I researched a lot about threading in the process of writing this article, but it seems that there are still various functions, and there may be ways to realize what I want to do other than those listed above. However, if I try to do it within the scope of my understanding, it will be as above. If this gets stuck, I'll try to find another way.

Recommended Posts

There is a pattern that the program did not stop when using Python threading
[Ev3dev] Create a program that captures the LCD (screen) using python
A program that plays rock-paper-scissors using Python
[Python] A program that rounds the score
Workaround for the problem that sys.argv is not passed when executing a Python script with only the file name in Python2.7 on Windows
Note that the Google Maps Android API GoogleMap.getProjection is not a singleton
There is a pattern that the program did not stop when using Python threading
[Python] A program that finds the minimum and maximum values without using methods
[Python] A program that counts the number of valleys
[Python] A program that compares the positions of kangaroos.
A story that was convenient when I tried using the python ip address module
Investigate the cause when an error is thrown when python3.8 is not found when using lambda-uploader with python3.8
Try to find the probability that it is a multiple of 3 and not a multiple of 5 when one is removed from a card with natural numbers 1 to 100 using Ruby and Python.
Python list is not a list
The story that `while queue` did not work in python
Is there a bias in the numbers that appear in the Fibonacci numbers?
[Python] A program that finds the most common bird types
A story that pyenv is stuck because the python execution command PATH does not pass
When writing to a csv file with python, a story that I made a mistake and did not meet the delivery date
When incrementing the value of a key that does not exist
Python will fail if there is a space after the backslash
Play a sound in Python assuming that the keyboard is a piano keyboard
I got a TypeError:'int' object is not iterable when using keras
Workaround for the problem that sys.argv is not passed when executing a Python script with only the file name in Python2.7 on Windows
The story that a hash error came out when using Pipenv
[Python] Appears when using iterdir () etc. [Errno 20] Not a directory:'*** / .DS_Store'
A program that determines whether a number entered in Python is a prime number
[Python] I tried to make a simple program that works on the command line using argparse.
The story that 2D list replacement did not work in python
Build Python environment on Ubuntu (when pip is not the default)
When writing a program in Python
[Python] A program that rotates the contents of the list to the left
Workaround for the problem that? Is displayed when checking the version when using non-standard perl | python with pkg version
[Python] Whiten the parts that turn black when there is no data in the Choropleth map of Folium.
A program that automatically determines whether an animation or a photo is entered when a person's image is input [python]
[Python] A program that calculates the number of chocolate segments that meet the conditions
Check points when MIDI does not work in a program using SDL_mixer
[Python] A program that calculates the number of socks to be paired
Note that the Google Maps Android API GoogleMap.getProjection is not a singleton
Notify using Notification Center when the execution environment is macOS in Python
A useful note when using Python for the first time in a while
Bug that says'val_loss' is not found when using Early Stopping in pytorch-lightning (0.5.3.2)
python note: when easy_install is not available
[Python] A program that creates stairs with #
It seems that the version of pyflakes is not the latest when flake8 is installed
Make a Python program a daemon and run it automatically when the OS starts
Are Php / Ruby / Python that only runs when the file is called directly
A story that did not end with exit when turning while with pipe input
Separately install a version of Python that is not pre-installed on your Mac
[Python] Solution to the problem that elements are linked when copying a list
[Python] A program that calculates the difference between the total numbers on the diagonal line.
Is there a contradiction between the party that protects the people from NHK and the party that protects NHK from the people?
A program that removes duplicate statements in Python
A program that searches for the same image
A shell program that displays the Fibonacci sequence
It is a piggybacking story about the service that returns "Nyan" when you ping
How to use pip, a package management system that is indispensable for using Python
A note on the library implementation that explores hyperparameters using Bayesian optimization in Python
[Python] A program that finds the shortest number of steps in a game that crosses clouds
To me who was confused because sudo python did not work when using virtualenv
A program that summarizes the transaction history csv data of SBI SECURITIES stocks [Python3]
A command to check when something goes wrong when the server is not doing anything
A note that runs an external program in Python and parses the resulting line