Thread lock, gil locks, deadlocks

Thread lock

from threading import Thread,Lock

x = 0
mutex = Lock()
def task(): global x # mutex.acquire() for i in range(200000): x = x+1 # t1 的 x刚拿到0 保存状态 就被切了 # t2 的 x拿到0 进行+1 1 # t1 又获得运行了 x = 0 +1 1 # 思考:一共加了几次1? 加了两次1 真实运算出来的数字本来应该+2 实际只+1 # 这就产生了数据安全问题. # mutex.release() if __name__ == '__main__': t1 = Thread(target=task) t2 = Thread(target=task) t3 = Thread(target=task) t1.start() t2.start() t3.start() t1.join() t2.join() t3.join() print(x) 

531388

We have talked about the process of the process lock, then thread-locking thread there, look at the code above, we know that threads share a process space, so they have to be increased x operation Logically, the result should be the last printed 600,000 , and here is far less because the thread performing the operation a long time, cup cut to the next thread, but this time may be x = 1000 + 1, 1 + performed only to 1000, so we saved this state, regardless of the back of the thread to do x plus a number of times, and finally returned to this thread will be reassigned to 1001.

So to add a thread lock, this process becomes plus serial, is a comment section. When he runs too long, cut to another thread, other threads can not get in, because the lock in the hands of the first thread. Therefore, this small piece of code that is sequential.

Deadlock

What is a deadlock:

Each other have the following code must continue to implement the conditions, and must get to the other side must be in the hands of his condition, then give each other the necessary conditions. Thus leading to each other can not continue.

The concept is my own summary, look at the code would be more clear:

from threading import Thread,Lock
import time
lock1=Lock()
lock2=Lock()
class Mythread1(Thread): def run(self): self.task1() def task1(self): lock1.acquire() print('a获得锁1') time.sleep(3) lock2.acquire() print('a获得锁2') lock1.release() print('a释放锁1') lock2.release() print('a释放锁2') class Mythread2(Thread): def run(self): self.task2() def task2(self): lock2.acquire() print('b获得锁2') time.sleep(3) lock1.acquire() print('b获得锁1') lock2.release() print('b释放锁2') lock1.release() print('b释放锁1') t1 =Mythread1() t1.start() t2=Mythread2() t2.start()

a lock is obtained. 1
B 2 obtained lock

Because ti got lock1, must first take lock2, but this time in the hands of lock2 t2, then t2 would have to wait to release lock2, and t2 release lock2 but must first get lock1, but this time in the hands of lock1 t1, which causing a deadlock.

Then look at the multi-threaded when the deadlock look.

from threading import Thread,Lock
mutex1 = Lock()
mutex2 = Lock()
import time
class MyThreada(Thread): def run(self): self.task1() self.task2() def task1(self): mutex1.acquire() print(f'{self.name} 抢到了 锁1 ') mutex2.acquire() print(f'{self.name} 抢到了 锁2 ') mutex2.release() print(f'{self.name} 释放了 锁2 ') mutex1.release() print(f'{self.name} 释放了 锁1 ') def task2(self): mutex2.acquire() print(f'{self.name} 抢到了 锁2 ') time.sleep(1) mutex1.acquire() print(f'{self.name} 抢到了 锁1 ') mutex1.release() print(f'{self.name} 释放了 锁1 ') mutex2.release() print(f'{self.name} 释放了 锁2 ') for i in range(3): t = MyThreada() t.start()

Thread-1 grab lock 1
Thread-1 grab lock 2
Thread-1 release lock 2
Thread-1 release lock 1
Thread-1 grab lock 2
the Thread-lock 1 2 grab

So how to solve the deadlock problem then, recursive lock.

Recursive lock

Recursive locks, in order to support Python, in the same thread multiple requests for the same resource, python provides reentrant lock RLock.

This internal RLock maintains a Lock and a counter variable, counter records the number of times acquire, so that resources can be many times require. Acquire a thread until all have been release, other threads to get resources. The above example if instead of using RLock Lock, deadlock will not occur.

mutex1 = RLock()
mutex2 = mutex1

import time
class MyThreada(Thread): def run(self): self.task1() self.task2() def task1(self): mutex1.acquire() print(f'{self.name} 抢到了 锁1 ') mutex2.acquire() print(f'{self.name} 抢到了 锁2 ') mutex2.release() print(f'{self.name} 释放了 锁2 ') mutex1.release() print(f'{self.name} 释放了 锁1 ') def task2(self): mutex2.acquire() print(f'{self.name} 抢到了 锁2 ') time.sleep(1) mutex1.acquire() print(f'{self.name} 抢到了 锁1 ') mutex1.release() print(f'{self.name} 释放了 锁1 ') mutex2.release() print(f'{self.name} 释放了 锁2 ') for i in range(3): t = MyThreada() t.start() 

Thread-1 grab lock. 1
Thread-1 grab lock 2
Thread-1 release lock 2
Thread-1 releases the lock. 1
Thread-1 grab lock 2
Thread-1 grab lock. 1
Thread-1 releases the lock. 1
the Thread -1 release lock 2
the Thread-lock 2 grab. 1
the Thread-lock grab 2 2
the Thread-2 release lock 2
the Thread-lock 2 is released. 1
the Thread-lock grab 2 2
the Thread-lock 2 grab. 1
the Thread- 2 to release the lock. 1
the Thread-2 release lock 2
the Thread-. 3 grab lock. 1
the Thread-. 3 grab lock 2
the Thread-. 3 release lock 2
the Thread-. 3 release the lock. 1
the Thread-. 3 grab lock 2
the Thread-. 3 grab lock. 1
the Thread-lock is released. 3. 1
the Thread-lock. 3 release 2

signal

from threading import Thread,currentThread,Semaphore
import time

def task(): sm.acquire() print(f'{currentThread().name} 在执行') time.sleep(3) sm.release() sm = Semaphore(5) for i in range(15): t = Thread(target=task) t.start()

He allowed that while the number of threads can get the lock.

GIL lock

There are a lock GIL (Global Interpreter Lock) in Cpython interpreter, GIl lock is essentially a mutex.
Led under the same process, the same time can only run one thread, you can not take advantage of multi-core advantage.
Multiple threads can only be achieved under the same process can not be achieved concurrent parallel.

Why should GIL?
Because cpython own garbage collection is not thread safe, so be GIL lock.

Led under the same process, the same time can only run one thread, you can not take advantage of multi-core advantage.
Analysis:
We have four tasks need to be addressed, treatment is certainly to play out the effect of concurrent solutions are:
Option One: open four processes
Option two: The next process, open four threads

Recommended for compute-intensive multi-process
each must be calculated 10s
multithreading
only one thread will be executed at the same time, it means that each province 10s can not, must be calculated separately for each 10s, were 40.ns
multi-process
parallel execution of multiple threads, 10s + open process time

io-intensive multi-threaded recommended
four tasks each task 90% most of the time io.
Each task io10s 0.5s
multi-threading
can be achieved concurrently, each thread io time is not ye take up cpu, 10s + 4 tasks of computing time
multi-process
can be implemented in parallel, time 10s + 1 task execution time + open process

Guess you like

Origin www.cnblogs.com/whnbky/p/11545995.html