Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do we need to use thread lock when there is only one thread? (python)

i don't understand why thread lock is used when there is only one thread. here is the code i've seen online isn't thread lock used only when there's more than 2 threads excluding main thread?

import socket
import threading

tLock = threading.Lock()
shutdown = False

def receving(name, sock):
    while not shutdown:
        try:
            tLock.acquire()
            while True:
                data, addr = sock.recvfrom(1024)
                print str(data)
        except:
            pass
        finally:
            tLock.release()

host = '127.0.0.1'
port = 0

server = ('127.0.0.1',5000)

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((host, port))
s.setblocking(0)

rT = threading.Thread(target=receving, args=("RecvThread",s))
rT.start()

alias = raw_input("Name: ")
message = raw_input(alias + "-> ")
while message != 'q':
    if message != '':
        s.sendto(alias + ": " + message, server)
    tLock.acquire()
    message = raw_input(alias + "-> ")
    tLock.release()
    time.sleep(0.2)

shudown = True
rT.join()
s.close()

also i do not understand why thread lock was used in this line

    tLock.acquire()
    message = raw_input(alias + "-> ")
    tLock.release()

what's going to happen if the thread lock was not used?

like image 852
hiyum Avatar asked May 04 '26 18:05

hiyum


2 Answers

The design of your program may be based on a flawed understanding of what locks are. If you expect that thread B will wake up from waiting to acquire a lock when thread A releases it, then you may be making a mistake. That's not quite how it works.

There are different ways that locking can work, but unless the documentation for the library that you are using promises more than the bare minimum (and, the doc for Python's Threading module does not make that promise), then the bare minimum is all you should only assume;

  • If thread A calls lck.acquire(), when lck is available, then the call will immediately succeed.

  • If thread A calls lck.release() while one or more other threads is blocked in an lck.acquire() call, then some time later, at least one of those threads will be allowed to re-try acquiring lck.

    • If the re-try is successful then the lck.acquire() call will return,
    • otherwise the thread will go back to waiting.

Here's a simplified version of your receive thread:

def receiving(name, sock):
    while not shutdown:
        tLock.acquire();
        data = sock.recvfrom(...);
        doSomethingWith(data);
        tLock.release();

Let's say, that the main thread is waiting in tLock.acquire() when a message arrives on sock. Here's what most likely happens:

receive thread
-------------------
receive the message
doSomethingWith(data)
tLock.release()
    - set status of tLock to "available"
    - Sees main thread is waiting for tLock
    - Changes state of main thread to RUNNABLE
    - returns.
tLock.acquire()
    - Sees that tLock is "available",
    - Changes it to "locked" and returns.
sock.recvfrom(...)
    - no message is immediately available,
    - goes into a wait state.

system heartbeat interrupt handler
----------------------------------
triggered by hardware
Sees that main thread is RUNNABLE
Kicks some other RUNNING thread off its CPU, and
   allows the main thread to start running on that CPU.

main thread
-----------
...still in a call to tLock.acquire()
    - sees that tLock still is "locked",
    - goes back to waiting.

That process can repeat itself many times without the tLock.acquire() call ever returning in the main thread.

This problem is an example of resource starvation.

like image 88
Solomon Slow Avatar answered May 06 '26 06:05

Solomon Slow


The lines here:

tLock.acquire()
message = raw_input(alias + "-> ")

effectively wait for a reply message from the server before prompting for the user to send a query/request up to the server

like image 22
quamrana Avatar answered May 06 '26 07:05

quamrana