LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-07-2023, 10:38 PM   #1
Turbocapitalist
LQ Guru
 
Registered: Apr 2005
Distribution: Linux Mint, Devuan, OpenBSD
Posts: 6,903
Blog Entries: 3

Rep: Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585
Restarting or replacing a stopped thread in Python3?


In the following, a thread is started which soon stops because of a raised exception. How can the main section detect when the thread has failed and create a new replacement, while keeping pause() in effect?

Code:
#!/usr/bin/env python3                                                          

from threading import Thread
from time import sleep
from signal import pause

def pool():
    while True:
        print("Threading")
        sleep(4)
        raise OSError("Uff da")

sample = Thread(target=pool, daemon=True, name="working")
sample.start()
pause()

Last edited by Turbocapitalist; 05-07-2023 at 11:12 PM. Reason: moved print()
 
Old 05-08-2023, 12:21 AM   #2
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 20,261

Rep: Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838
Code:
 signal.pause()
    Cause the process to sleep until a signal is received; the appropriate handler will then be called. Returns nothing.
So you need to replace pause and check the threads (if they are running or exited somehow) repeatedly, see here (for example): https://superfastpython.com/thread-wait-for-result/
 
Old 05-08-2023, 12:50 AM   #3
Turbocapitalist
LQ Guru
 
Registered: Apr 2005
Distribution: Linux Mint, Devuan, OpenBSD
Posts: 6,903

Original Poster
Blog Entries: 3

Rep: Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585
Thanks. I'm not sure it would be feasible to replace pause() there. The above is a very simplified version of a more complicated script which is having the trouble. The pause() is a stand-in for mqtt.loop_forever() from paho.mqtt.client though maybe there is another approach using mqtt.loop_start() instead.
 
Old 05-08-2023, 01:08 AM   #4
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 20,261

Rep: Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838
Code:
    def loop_forever(self, timeout=1.0, max_packets=1, retry_first_connection=False):
        """This function calls the network loop functions for you in an
        infinite blocking loop. It is useful for the case where you only want
        to run the MQTT client loop in your program.
You cannot use loop_forever in a multithreaded environment.
 
Old 05-08-2023, 01:25 AM   #5
Turbocapitalist
LQ Guru
 
Registered: Apr 2005
Distribution: Linux Mint, Devuan, OpenBSD
Posts: 6,903

Original Poster
Blog Entries: 3

Rep: Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585
Thanks. I'll try with something similar to the following. The old script tended to fail one every week or two, so it'll be a while before it'll be seen if there is an improvement.

Code:
#!/usr/bin/env python3

from threading import Thread
from time import sleep
import signal

def handler(signum, frame):
    signame = signal.Signals(signum).name
    print(" OK",signame)
    exit(0)

def pool():
    while True:
        print("Threading")
        sleep(4)
        raise OSError("Uff da")

signal.signal(signal.SIGINT, handler)

# add mqtt loop_start() here

while True:
    process_thread = Thread(target=pool,
                        daemon=True,
                        name="working")
    process_thread.start()
    process_thread.join()
 
Old 05-08-2023, 02:03 AM   #6
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 20,261

Rep: Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838
you have to dump all relevant parts into a logfile, including the full exception trace/message
 
Old 05-08-2023, 02:08 AM   #7
Turbocapitalist
LQ Guru
 
Registered: Apr 2005
Distribution: Linux Mint, Devuan, OpenBSD
Posts: 6,903

Original Poster
Blog Entries: 3

Rep: Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585
Quote:
Originally Posted by pan64 View Post
you have to dump all relevant parts into a logfile, including the full exception trace/message
I tracked that down already: There are some static system files which are, apparently, temporarily unreadable once every few weeks. So the real problem may be with the OS but since that is Raspberry Pi OS, fat chance of getting it fixed. Better to wait for the next edition instead and try some work-arounds until then.

The two work-arounds would be the above modification and to move the reading up in the script so that it happens once per session and not once per nested loop.
 
Old 05-08-2023, 02:12 AM   #8
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 20,261

Rep: Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838
hm. I don't really understand that (how can a static system file disappear), but such problems [probably] can be solved with a simple retry.
 
Old 05-08-2023, 02:17 AM   #9
Turbocapitalist
LQ Guru
 
Registered: Apr 2005
Distribution: Linux Mint, Devuan, OpenBSD
Posts: 6,903

Original Poster
Blog Entries: 3

Rep: Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585
Quote:
Originally Posted by pan64 View Post
hm. I don't really understand that (how can a static system file disappear), but such problems [probably] can be solved with a simple retry.
Yes, a third work-around would be to wrap the relevant lines in a try: conditional, but I'll use the above two for now.

I don't know that the the system file actually disappears, just that every once in a very rare while trying to read it results in an OSError exception. I tried running strace on the whole script but since it kept running even after the thread raised an exception, I could not capture what had gone on precisely. Though if it happen again, I'll add some removable storage and capture the strace output to it.
 
Old 05-08-2023, 03:20 AM   #10
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 20,261

Rep: Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838Reputation: 6838
that may mean concurrent [write] access to that file, like logs or similar, but without details hard to say more.
 
Old 05-08-2023, 09:28 AM   #11
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,253
Blog Entries: 4

Rep: Reputation: 3777Reputation: 3777Reputation: 3777Reputation: 3777Reputation: 3777Reputation: 3777Reputation: 3777Reputation: 3777Reputation: 3777Reputation: 3777Reputation: 3777
See this:

https://stackoverflow.com/questions/...er-or-a-signal


Another strategy is to create a thread which does nothing but sleep() and then signal the parent thread in an endless loop.
 
Old 05-08-2023, 09:32 AM   #12
Turbocapitalist
LQ Guru
 
Registered: Apr 2005
Distribution: Linux Mint, Devuan, OpenBSD
Posts: 6,903

Original Poster
Blog Entries: 3

Rep: Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585Reputation: 3585
Thanks. I'll look into .Event() and see if I can both figure it out and if it would help.

I generally avoid stankoverflow posts since looking at the few topics I know about shows that it's a site full of wrong answers.
 
Old 05-08-2023, 03:23 PM   #13
teckk
Senior Member
 
Registered: Oct 2004
Distribution: Arch
Posts: 4,796
Blog Entries: 6

Rep: Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711
Quote:
How can the main section detect when the thread has failed and create a new replacement, while keeping pause() in effect?
If I understand what you are wanting.
Code:
#!/usr/bin/python

#Lock thread example with Queue
#Lock thread and wait until all items are processed. No race condition. No other
#thread can write at the same time.

from threading import Thread, Lock, current_thread
from queue import Queue
from time import sleep

def worker(q, lock):
    #Inf loop, wait until available
    while True:
        value = q.get()
        with lock:
            print(f'In {current_thread().name} got Value {value}')
        q.task_done()
        sleep(1)
        
if __name__ == "__main__":
    
    q = Queue()
    lock = Lock()
    
    num_threads = 10
    
    for i in range(num_threads):
        thread = Thread(target=worker, args=(q, lock))
        thread.daemon=True
        thread.start()
    
    for i in range(1, 21):
        q.put(i)
        
    q.join()
 
Old 05-08-2023, 03:46 PM   #14
dugan
LQ Guru
 
Registered: Nov 2003
Location: Canada
Distribution: distro hopper
Posts: 10,964

Rep: Reputation: 5217Reputation: 5217Reputation: 5217Reputation: 5217Reputation: 5217Reputation: 5217Reputation: 5217Reputation: 5217Reputation: 5217Reputation: 5217Reputation: 5217
So you just want one thread at a time, and each one starts when the previous one exits?

This works:

Code:
#!/usr/bin/env python3

import threading
import time

lock = threading.Lock()


def hello():
    lock.acquire()
    time.sleep(1)
    print("Hello world")
    lock.release()


for _ in range(5):
    t = threading.Thread(target=hello)
    t.start()
If something in the thread can throw an exception, you need to catch it.

Last edited by dugan; 05-08-2023 at 03:54 PM.
 
Old 05-08-2023, 04:16 PM   #15
teckk
Senior Member
 
Registered: Oct 2004
Distribution: Arch
Posts: 4,796
Blog Entries: 6

Rep: Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711Reputation: 1711
Code:
#!/usr/bin/python

#Processes like threads don't live in the same memory space. They need shared memory objects.
#These processes may try to access the same shared variable at the same time

from multiprocessing import Process, Value, Array
import os
from time import sleep
 
def add_100(number):
    for i in range(100):
        sleep(.01)
        number.value += 1
        
if __name__ == "__main__":
    shared_number = Value('i', 0)
    print('Number at beginning is', shared_number.value) 
    
    p1 = Process(target=add_100, args=(shared_number,))
    p2 = Process(target=add_100, args=(shared_number,))
     
    p1.start()
    p2.start()
    
    p1.join()
    p2.join()
    
    print('Number at end is', shared_number.value)
        
        
#Lock them
#These won't walk on each other.

from multiprocessing import Process, Value, Array, Lock
import os
from time import sleep 
        
def add_100(number, lock):
    for i in range(100):
        sleep(.01)
        lock.acquire()
        number.value += 1
        lock.release() 
        
if __name__ == "__main__":
    
    lock = Lock()
    shared_number = Value('i', 0)
    print('Number at beginning is', shared_number.value) 
    
    p1 = Process(target=add_100, args=(shared_number, lock))
    p2 = Process(target=add_100, args=(shared_number, lock))
     
    p1.start()
    p2.start()
    
    p1.join()
    p2.join()
    
    print('Number at end is', shared_number.value)
 
1 members found this post helpful.
  


Reply

Tags
python3, threading


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
python3 -V returns Python 2.7.12, can't get python3 to work. gene_ Ubuntu 15 03-18-2019 10:39 AM
[SOLVED] making python3.6.4 default python3 Astral Axiom Linux - Newbie 17 04-14-2018 10:55 AM
[SOLVED] how to start python3.6 interpreter just by typing python in terminal not python3.6 bmohanraj91 Linux - Newbie 4 05-10-2017 07:51 AM
After upgrade python3.4 to python3.5.1 , not able to install packages "request" though pip3 YOGESHAS87 Linux - Software 1 08-03-2016 10:38 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 06:39 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration