Проблема с синхронизацией потоков

Рейтинг: 0Ответов: 2Опубликовано: 08.06.2023

У меня возникла проблема с синхронизацией потоков. Мне нужно сделать так, чтобы код мог завершаться по просьбе пользователя. У меня есть 3 метода в коде: первый - отвечающий за запуск самого сервера, второй - отвечающий за поддержку клиента (получение данных от клиента) и, наконец, третий - отвечающий за запрос у пользователя, хочет ли он закрыть программу. Однако даже если пользователь введёт no или что-либо кроме no, цикл в методе start_server все равно продолжит работать, ибо флаг в нём не обновляется (из за того, что методы с потоками не синхронизированы). А вот как мне синхронизировать их так, чтобы код завершался по зову/просьбе/желанию пользователя, я не знаю. Буду благодарен, если кто-нибудь мне поможет.

Код:

import socket
import threading


class Server:
    def __init__(self, host, port):
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.host = host
        self.port = port
        self.flag = True
        self.locker = threading.Lock()

    def start_server(self):
        self.server.bind((self.host, self.port))
        self.server.listen(5)
        print("Created the server")

        while self.flag:
            print("Waiting when client connects")
            client, _ = self.server.accept()
            print("Client connected")
            t = threading.Thread(target=self.handle_client, args=(client,))
            t.start()

    def handle_client(self, client):
        while self.flag:
            data = client.recv(4096)
            data = data.decode("utf-8")
            if data:
                print(f"Data received: \n{data}")
                self.continue_program()

    def continue_program(self):
        con_inp = input("Continue(yes,no)?: ")
        if con_inp.lower() in ["yes", "y"]:
            return
        else:
            self.flag = False


if __name__ == "__main__":
    obj_server = Server("127.0.0.1", 8080)
    obj_server.start_server()

Ответы

▲ 0Принят

Итак, в общем, я наконец смог решить проблему. Оказывается, нужно было использовать condition в threading. Я немного отредактировал код. Мне помог по факту решить проблему человек с юзернеймом: user207200. Я задал немного иначе вопрос, после чего получил ответ. Я изменил код по аналогии, как и в ответе и, наконец, получил желаемый результат.

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

import socket
import threading


class Server:
    def __init__(self, host, port):
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.host = host
        self.port = port
        self.flag = True
        self.condition = threading.Condition()

    def create_server(self):
        self.server.bind((self.host, self.port))
        self.server.listen(10)
        print("Created the server successfully")

    def accept_client(self):
        while self.flag:
            print("Waiting for client connection")
            client, _ = self.server.accept()
            print("Client connected")
            t = threading.Thread(target=self.handle_client, args=(client,))
            t.start()
            self.condition.acquire()
            self.condition.wait()
            self.condition.release()

    def handle_client(self, client):
        while self.flag:
            data = client.recv(4096).decode("utf-8")
            if data:
                print("Data received:\n", data)
            else:
                break

            self.continue_program()

    def continue_program(self):
        con_inp = input("Continue?: ")
        if con_inp.lower().strip() in ["yes", "y"]:
            ...
        else:
            self.flag = False

        self.condition.acquire()
        self.condition.notify_all()
        self.condition.release()

        return

    def run(self):
        self.create_server()
        self.accept_client()

if __name__ == "__main__":
    s = Server("127.0.0.1", 8080)
    s.run()
▲ 0

Можно попробовать так Добавлена with self.locker, которая захватывает блокировку self.locker

import socket
import threading


class Server:
    def __init__(self, host, port):
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.host = host
        self.port = port
        self.flag = True
        self.locker = threading.Lock()

    def start_server(self):
        self.server.bind((self.host, self.port))
        self.server.listen(5)
        print("Created the server")

        while self.flag:
            print("Waiting for client connection")
            client, _ = self.server.accept()
            print("Client connected")
            t = threading.Thread(target=self.handle_client, args=(client,))
            t.start()

    def handle_client(self, client):
        while self.flag:
            data = client.recv(4096)
            data = data.decode("utf-8")
            if data:
                print(f"Data received: \n{data}")
                self.continue_program()

    def continue_program(self):
        with self.locker:
            con_inp = input("Continue (yes/no)?: ")
            if con_inp.lower() in ["yes", "y"]:
                return
            else:
                self.flag = False


if __name__ == "__main__":
    obj_server = Server("127.0.0.1", 8080)
    obj_server.start_server()