import time
import threading

### Базовое использование потоков

def get_data_1(data):
    while True:
        print(f"<< вывод из другого потока {threading.current_thread().name} - {data}>>")
        time.sleep(1)
        data = str(time.time())

def thread_test_1():
    thr = threading.Thread(target=get_data_1, args=(str(time.time()), ), name="Thr-1")
    thr.start()

    ite = 0
    while True:
        time.sleep(3)
        print(f"\n\n Вывод №{(ite:= ite+1)}: ")
        print(f"Наш личный поток работает?: {thr.is_alive()}")
        for ind, val in enumerate(threading.enumerate()):
            print(f"\t Активный поток №{ind+1}: {val}")
        print("\n\n")

### Демонстрация выполнения ТОЛЬКО по завершению работы (ф-я join)

def get_data_2(data, value):
    for _ in range(value):
        print(f"<{threading.current_thread().name} - d:{data}, v:{value}> ")
        time.sleep(1)

def thread_test_2():
    start_val, end_val = 1, 5
    
    # создаем функцию которая создает потоки
    tc = lambda x: threading.Thread(target=get_data_2, args=(str(time.time()), x,), name=f"thr-{x}", daemon=True)
    
    # создаем список потоков
    thr_list = [tc(x) for x in range(start_val, end_val + 1)]
    
    # запускаем потоки
    [x.start() for x in thr_list]
    
    # Ждем пока они завершаться (программа не дойдет до финиша, пока все потоки не завершат раобту)
    for i in thr_list:
        i.join()
    print("finish")


# thread_test_2()

### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Синхронизация потоков. Блокировка отоков.z

# value = 0
# locker = threading.Lock() # locker может использовать любой поток
# rlocker = threading.RLock() # может разблокировать только тот поток, который вызвал блокировку


def inc_value():
    global value
    while True:
        locker.acquire()
        value += 1
        print(value)
        time.sleep(1)
        locker.release()

def inc_value_with():
    global value
    while True:
        with locker:
            value += 1
            print(value)
            time.sleep(0.1)
            locker.release()


# for _ in range(5):
#     threading.Thread(target=inc_value).start()


### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Таймеры

def timer_output():
    while True:
        print("test")
        time.sleep(1)

def timer_start():
    thr = threading.Timer(5, timer_output)
    thr.daemon = True # Поток будет завершен после завершения основого потока
    thr.start()

    # thr.cancel()    # отменить поток


    while True:
        print("main")
        time.sleep(1)

# timer_start()    


### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### local Хранение данных и атрибуты

data = threading.local()

def get_data():
    print(data.value)

def data_thread_1():
    data.value = 111
    get_data()
    print("t1:", data.value)

def data_thread_2():
    data.value = 222
    get_data()
    print("t2:", data.value)

def start_data_threads():
    threading.Thread(target=data_thread_1).start()
    threading.Thread(target=data_thread_2).start()

start_data_threads()