как правильно использовать Thread. многопоточность

введите сюда описание изображенияВ моем мини (проекте) по создании меню для игры. Пока меню активна то сокет ожидает подключение для сетевой игры. мне нужно три функции одновременно запустить но почему то когда запущены. и я выхожу из игры через красный крестик то зависает ошибка Не знаю в чем проблема как решить

from pygame import display, draw, mouse, event, QUIT, Rect
from main import W, H
from threading import Thread
from time import sleep
import socket

screen = display.set_mode((W, H))
start_btn = Rect(W/2-200, H/2-80, 200, 80)

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('', 9531))
server.listen(2)
break_server = False

num_users = []

def acc():
    while True:
        conn, addr = server.accept()
        num_users.append(conn)
def keep_users():
    while True:
        if num_users:
            print('run')
            for conn in num_users:
                try:    conn.send('/.,'.encode())
                except: num_users.remove(conn)
                print(conn)
            sleep(0.5)


def menu():
    global break_server
    while not break_server:
        display.update()
        screen.fill((150, 150, 150))
        draw.rect(screen, 'Blue', start_btn)

        if mouse.get_pressed()[0] and start_btn.collidepoint(mouse.get_pos()):
            print('ВСЕ')
            break_server = True
        for i in event.get():
            if i.type == QUIT:
                break_server = True


Thread(target=menu).start()
Thread(target=acc).start()
Thread(target=keep_users).start()

Ответы (1 шт):

Автор решения: gord1402

Процесс будет завершён только когда все потоки будут остановлены, у вас же после завершения main потоки продолжают действовать.

Начнём с keep_users, здесь достаточно добавить условие завершения цикла.

Теперь acc, поскольку server.accept() - долгая функция вам прийдётся ждать до её завершения для проверки break_server, однако можно использовать поток-демон, такой поток завершится, когда все родительские потоки завершатся.

Вот изменённый код:

from pygame import display, draw, mouse, event, QUIT, Rect
from threading import Thread
from time import sleep
import socket

W, H = 640, 480

screen = display.set_mode((W, H))
start_btn = Rect(W / 2 - 200, H / 2 - 80, 200, 80)

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('', 9531))
server.listen(2)
break_server = False

num_users = []


def acc():
    while not break_server:
        conn, addr = server.accept()
        num_users.append(conn)


def keep_users():
    # Стоит смотреть когда основной поток остановлен, вместо вечного цикла
    while not break_server:
        if num_users:
            print('run')
            for conn in num_users:
                try:
                    conn.send('/.,'.encode())
                except:
                    num_users.remove(conn)
                print(conn)
            sleep(0.5)


def menu():
    global break_server
    while not break_server:
        display.update()
        screen.fill((150, 150, 150))
        draw.rect(screen, 'Blue', start_btn)

        if mouse.get_pressed()[0] and start_btn.collidepoint(mouse.get_pos()):
            print('ВСЕ')
            break_server = True
        for i in event.get():
            if i.type == QUIT:
                break_server = True


# Поток-демон завершится когда все потоки не демоны завершатся
acc_thread = Thread(target=acc, daemon=True)
keep_users_thread = Thread(target=keep_users)

# Сначала запускаем потоки
acc_thread.start()
keep_users_thread.start()

# В главном потоке запускаем GUI
menu()

# После завершения GUI, ждём завершения keep_users_thread в главном потоке
keep_users_thread.join()

# Поток acc_thread завершится сам даже если будет в середине выполнения
→ Ссылка