If I find time I can try to run the program on my Windows machine and see if I get the same results. Not sure when I'll be able to do that. I'm suffering in great pain right now from a strange new disease called Covid-19. It's not fun trying to do anything with all this pain. I spend the vast majority of my time lately laying in bed moaning in agony. The people who say you don't want to get this are right on!
James, I am so sorry to hear that you are going through this. Please get the rest and treatment you need, while we all value your input to the forum, your health is the number one priority.
If you want to chat you can PM me and you have my email. And if there is anything at all that I can do for you please let me know.
Bill
"Never trust a computer you can’t throw out a window." — Steve Wozniak
Firstly, I did some research on processes vs threads and again I find that threading is more applicable to GUI programs, specifically to keep them responsive, and allow threads to communicate easily among GUI components, unlike processes which operate as separate program instances - My recordings below will show this in terms of memory usage.
Very simple program, and no reason for it to work differently on either O/S, but we'll find out after testing.
Ok, to this issue, I have found out that Linux does in fact manage processes differently to Windows, but this is not a real problem as we will see.
Because of the way Windows manages processes, Windows is actually showing up the error as a new GUI, whereas Linux is hiding it from you, and you're just not seeing it without detailed investigation.
I have amended my small test program to show this detail as follows:
from tkinter import *
from tkinter import Button
import threading
from multiprocessing import Process
import time
import subprocess as CMD
def runAsNewProcess():
time.sleep(5)
def createProcess1():
p1 = threading.Thread(target=runAsNewProcess)
#p1 = Process(target=runAsNewProcess)
p1.start()
def createProcess2():
command = "ls"
p2 = threading.Thread(target=CMD.call((command), shell=True))
#p2 = Process(target=CMD.call((command), shell=True))
p2.start()
root = Tk()
button1 = Button(root, text="Create New PROCESS 1", command=createProcess1)
button1.pack()
button2 = Button(root, text="Create New PROCESS 2", command=createProcess2)
button2.pack()
root.mainloop()
I will demonstrate this program below with some screen recordings.
Yes, a when you want a separate process, calling process will give it to you, but it will also give you a brand new python interpreter along with it, as a process is actually a new program instance
But raspivid isn't a Python program, so it doesn't require a Python interpreter. I think I see the problem. I actually suspected this when I first wrote the program, but since the program was working for me I didn't see it as being a problem.
It doesn't really matter what raspivid is... when you create a new process, a new interpreter is created for that process - You'll see the processes in action in my screen recordings below.
def runAsNewProcess():
passdef createProcess():
command = "terminal command to launch raspivid"
p = Process(target=subprocess.call((command), shell=True))
p.start()By doing it this way, the new process should be raspivid directly, no Python methods involved.
That's not what happens during testing, as you'll see in my screen recordings below.
By the way, the reason is works with threading is because you are creating a new thread to run the method runAsNewProcess().
Then that new thread launches raspivid and just "hangs up" until raspivid has been terminated. Only then is control returned to the runAsNewProcess() method which then quits.
No, the threads are a part of the process. It's the processes that actually hang up after they run and become zombie processes <defunct> processes. Here is what the Linux man page has to say about them, and my recordings will show that's exactly what is happening when using processes - This means that the processes are completing as soon as they are created - I added a sleep in my code example to show exactly that happening.
From the man page:
Processes marked <defunct> are dead processes (so-called "zombies") that remain because their parent has not destroyed them properly. These processes will be destroyed by init(8) if the parent process exits.
[snip]
Z defunct ("zombie") process, terminated but not reaped by its parent
Also check out the following link regarding defunct processes. The page also mentions that: "Unix manages an explicit parent-child relationships between processes (Windows does not do this)."
Here are some recordings to show what's going on:
This first recording shows the processes in action, when clicking the buttons on the python GUI - Notice how every new process creates a new PID, and recreates the same size of new memory as the original process? This is a new python interpreter and program instance being created every time.
However, using processes still become <defunct>, even if put under the one method as per your last example, which suggests by nature of the results shown, that by the time you come around to click the stop/kill button, it's not really in a new process at all, because it's long become <defunct> (a dead process):
This second recording shows the threading in action, when clicking the buttons on the python GUI - In this version there is only ever one PID, and multiple clicks of the buttons show that the memory grows, but the process is the same memory space for each new thread, and there are no <defunct> processes created.
Note:- These are GIF files, and may not run on this page, so you may need to just save them and run them locally to see the recordings in action. If you don't wish to do that, you can run the program yourself from one shell, and then in another shell run the following command to view the live processes in action:
watch -n 1 "ps u -C python3"
I think this clarifies the problem, and why I was experiencing it under windows.
Cheers.