### Lock

When reading and writing data globally, if atomic operations cannot be guaranteed, it is easy to pollute the data.
Such as:

```import threading
import time

l = 
def func():
num = l
time.sleep(0.001)
l = num + 1

if __name__ == '__main__':
for i in range(100):
print(l)
```

The printed result is , which means that the data has been polluted.
The solution is to add lock:

```import threading
import time

l = 
lock = Lock()
def func():
lock.acquire()
num = l
time.sleep(0.001)
l = num + 1
lock.acquire()

# You can also use the with statement
def func2():
with lock:
num = l
time.sleep(0.001)
l = num + 1

if __name__ == '__main__':
for i in range(100):
print(l)
```

The result printed after execution is 

### RLock

The program has multiple locks, or the recursion causes the lock to be unable to be released or acquired.

```import threading
import time

num = 5
lock = Lock()
def func():
global num
with lock:
if num == 1:
print(num)
return
num -= 1
print(num)
func()

if __name__ == '__main__':
for i in range(2):

```

Run the program, the program will be blocked, it should enter the recursion after the first layer gets the lock, and the function of the second recursion cannot get the lock unless it is forced to exit.
Solution:
Use RLock locks. (In fact, it is enough to recurse after the lock is cast, here to demonstrate the function of RLock)

```import threading
import time

num = 5
lock = RLock()
def func():
global num
with lock:
if num == 1:
return
num -= 1
print(num)
func()

if __name__ == '__main__':
for i in range(2):

```

The result of running the program is 4, 3, 2, 1

### Condition

When there are many threads, Lock will repeatedly lock and unlock, which consumes a lot of CPU resources. Condition is used to solve this problem.

```import time
import random

num = 1000
super(Parents, self).__init__()
self.condition = condition

def run(self):
global num
while 1:
self.condition.acquire()
plus_num = random.randint(0, 200)
num = num + plus_num
print('%s has increased%s,The amount is now%s' % (self.thread_name, plus_num, num))
# Notify all threads that production has ended
self.condition.notify_all()
self.condition.release()
time.sleep(.5)

super(Children, self).__init__()
self.condition = condition

def run(self):
global num
while 1:
self.condition.acquire()
plus_num = random.randint(200, 500)
# Every time you connect to a notification, you need to check whether the conditions are met
while num - plus_num < 0:
print('%s need to consume%s，Insufficient remaining amount, waiting for production' % (self.thread_name, plus_num))
# Equal production with parents
self.condition.wait()
num = num - plus_num
print('%s have consumed%s,The amount is now%s' % (self.thread_name, plus_num, num))
self.condition.release()
time.sleep(.5)

Parents(condition, 'mather').start()
Parents(condition, 'father').start()
Children(condition, 'daughter').start()
Children(condition, 'son').start()
```

output result

```mather 199 has been added,The amount is now 1199
father 63 has been added,The amount is now 1262
daughter 218 have been consumed,The amount is now 1044
son 477 spent,The amount is now 567
father 116 has been added,The amount is now 683
daughter 304 has been consumed,The amount is now 379
mather has increased by 60,The amount is now 439
son 329 spent,The amount is now 110
daughter Need to consume 394, the remaining amount is insufficient, waiting for production
father 74 has been added,The amount is now 184
mather 163 has been added,The amount is now 347
daughter Need to consume 394, the remaining amount is insufficient, waiting for production
```

### Semaphore

Semaphore is similar to Lock. The difference is that Semaphore can have multiple processes set to acquire at the same time. When the acquired process reaches the set number, there must be a process release to have a new process acquire.

```import time
import random

super().__init__()
self.semaphore = semaphore

def run(self):
self.semaphore.acquire()
time.sleep(random.randint(2, 5))
self.semaphore.release()

for i in range(100):
Sem(i, semaphore).start()
```

Some of the results are as follows:

```0 is runing
1 is runing
1 is end
0 is end
2 is runing
3 is runing
2 is end
4 is runing
3 is end
5 is runing
```

It can be seen that the thread must end before a new thread can start.

### Event

The Event class can determine the blocking of other processes by setting the Boolean value of the Flag through an event thread. For example, in the famous traffic light event, whether the car process is carried out is determined by the traffic light event process:

```import time
import random

def __init__(self, event):
super().__init__()
self.event = event

def red(self):
print("Traffic-light is red now!")
# Red light is on, set flag to False
self.event.clear()

def green(self):
print('Traffic-light is green now!')
# Green light is on, set flag to True
self.event.set()

def run(self):
while 1:
self.red()
time.sleep(5)
self.green()
time.sleep(20)

def __init__(self, event, i):
super(Car, self).__init__()
self.event = event
self.i = i

def run(self):
if not self.event.is_set():
# If the flag is Fasle then wait for the red light.
print('Car %s is waiting' % self.i)
self.event.wait()
# pass
print('Car %s is crossing' % self.i)

event = Event()

Light(event).start()
for i in range(100):
time.sleep(random.randint(0, 10))
Car(event, i).start()
```

Some of the results are as follows:

```Traffic-light is red now!
Traffic-light is green now!
Car 0 is crossing
Car 1 is crossing
Car 2 is crossing
Car 3 is crossing
Car 4 is crossing
Traffic-light is red now!
Car 5 is waiting
Car 6 is waiting
Traffic-light is green now!
Car 6 is crossing
Car 5 is crossing
```

### Timer

Timer is a timer, which is used to start threads regularly:

```import time

print(time.ctime())

```

If you need to start cyclically, you can add a timer to the task, so that a task can be started every 2 seconds.

```import time