简体   繁体   English

如何同步线程以便它们响应用户输入?

[英]How to synchronize threads so that they respond to user input?

I have an assignment from school to program a guessing game.我有一项来自学校的作业,要编写一个猜谜游戏。 The player/user connects to the server , starts the game and guesses a word.玩家/用户连接到server ,开始游戏并猜一个词。 If he guesses the word, he wins.如果他猜对了这个词,他就赢了。 Multiple players/users can join the game(Later I will limit to a reasonable number, like 3).多个玩家/用户可以加入游戏(稍后我会限制在一个合理的数量,比如 3 个)。 Client connects via putty客户端通过putty连接

In this task I need to use multiple threads and then synchronize them somehow.在此任务中,我需要使用多个threads ,然后以某种方式同步它们。 Let's take into account that there are 3 players playing.让我们考虑到有 3 名玩家在玩。 The first player guesses, enters his guess, and I want the other two players to wait while the player enters his guess.第一个玩家猜测,输入他的猜测,我希望其他两个玩家在玩家输入他的猜测时等待。 Then the 2nd player can guess, after the 2nd player the 3rd player, etc..然后第二个玩家可以猜,第二个玩家之后第三个玩家,等等。

My primary guess a) How do I do this?我的主要猜测a) 我该怎么做? I used Join , but I don't know if it accomplishes what I want我使用了Join ,但我不知道它是否完成了我想要的

b)Is this style of play(Waiting for players to next guess) at all good for the example with thread work? b) 这种游戏风格(等待玩家下一次猜测)是否适合线程工作的示例?

Server class:服务器类:

 /// <summary>
        /// Constuctor for creating server for players. 
        /// 
        /// </summary>
        /// <param name="port">
        /// Port for connecting to the server
        /// 
        /// </param>
        public Server(int port)
        {
            myServer = new TcpListener(IPAddress.Any, port);
            myServer.Start();
            isRunning = true;
            LoopServer();
        }
 /// <summary>
        /// Every time a new user connects to the server, a new thread is created.
        /// </summary>
        private void LoopServer()
        {
            while (isRunning)
            {
                TcpClient client = myServer.AcceptTcpClient();
                Thread thread = new Thread(new ParameterizedThreadStart(LoopClient));
                thread.Start(client);
                thread.Join();
            }
        }
/// <summary>
       /// Method where is game played
       /// </summary>
       /// <param name="obj"></param>
        private void LoopClient(object obj)
        {
           
            try
            {
                TcpClient client = (TcpClient)obj;
                StreamReader reader = new StreamReader(client.GetStream(), Encoding.UTF8);
                StreamWriter writer = new StreamWriter(client.GetStream(), Encoding.UTF8);
                users.Add(new User(Thread.CurrentThread.ManagedThreadId));
                writer.Flush();

                puzzle.guessWord( writer, reader,users );
                Console.WriteLine("Out of the server");



            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

Game class:游戏类:

 /// <summary>
        /// Everytime player/user take guess, the strign is added to list of user's gusses
        /// </summary>
        /// <param name="user">
        /// </param>
        /// <param name="userGuess"></param>
        /// <returns>
        /// Returns what is user's guess(string) and who took the guess(id)
        /// </returns>
        public string TakeGuess(User user, string userGuess)
        {
            user.Guesses.Add(Validation(userGuess));
            return "Your guess:" + userGuess + " " + "player with id:" + user.Id;
        }
 /// <summary>
        /// Here is the method in which the game itself is played.
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="reader"></param>
        /// <param name="users"></param>
        public void guessWord(StreamWriter writer, StreamReader reader, List<User> users)
        {
            Console.Write("Connected");
            bool gameIsPlaying = true;
            //Creates new User. The player's id indicates which thread the player is using
            User user = new User(Thread.CurrentThread.ManagedThreadId);

            writer.WriteLine("Guessing game");

            Console.WriteLine("Number of players in game:" + " "+  users.Count);
            if (users.Count > 0)
            {
                while (gameIsPlaying)
                {
                    string data = reader.ReadLine();
                    //Whatever what writer object print, shows on client side(in putty)
                    writer.WriteLine(TakeGuess(user, data));

                    if (Validation(data).Equals(this.Word))
                    {
                        gameIsPlaying = false;
                        Console.WriteLine("Winner is user with id" + " " + user.Id);
                        writer.WriteLine("Winner is user with id"+ " " + user.Id);
                        users.Clear();
                    }


                }

                writer.WriteLine("The game is over");

            }
        }

I have tried to synchronize threads(platers/users as I have described in the text above)我试图同步线程(如我在上面的文本中所述的电镀机/用户)

This is your homework, so I'll just give a few hints:这是你的作业,所以我只给出一些提示:

users.Add(new User(Thread.CurrentThread.ManagedThreadId));
writer.Flush();

I'm assuming users is of type List<User> .我假设users的类型是List<User> That type is not thread safe, so you need a lock when accessing it, or the behavior will be undefined if multiple users log on simultaneously.该类型不是线程安全的,因此在访问它时需要加锁,否则如果多个用户同时登录,行为将是未定义的。

puzzle.guessWord( writer, reader, users );

Here, you should forward the current user, not the list of users (that one is in this context global anyway).在这里,您应该转发当前用户,而不是用户列表(无论如何在这个上下文中是全局的)。

//Creates new User. The player's id indicates which thread the player is using
User user = new User(Thread.CurrentThread.ManagedThreadId);

That's wrong.那是错误的。 You already created the user for this thread, so use it.您已经为此线程创建了用户,因此请使用它。 The user given in the argument (see above) is the current user.参数中给出的用户(见上文)是当前用户。

                while (gameIsPlaying)
                {
                    string data = reader.ReadLine();
                    //Whatever what writer object print, shows on client side(in putty)
                    writer.WriteLine(TakeGuess(user, data));

                    if (Validation(data).Equals(this.Word))
                    {
                        gameIsPlaying = false;
                        // ...
                    }
                }

Here you need to identify the user whose turn it is.在这里,您需要确定轮到谁的用户。 So keep a member variable with the ID of the user that is next (note that there's only one instance of the Game class, but it runs many threads).因此,保留一个带有下一个用户 ID 的成员变量(请注意,Game 类只有一个实例,但它运行许多线程)。 Protect that variable with a lock.用锁保护该变量。 On each iteration of the loop, check whether it's our turn.在循环的每次迭代中,检查是否轮到我们了。 If yes, ask for the guess.如果是,请猜猜。 If no, output something that says "Please wait for player XY", wait a bit and try again.如果不是,则输出“请等待玩家 XY”的内容,稍等片刻再试。 Of course, you can also do more sophisticated things like using a Semaphore.当然,您也可以做更复杂的事情,比如使用信号量。 That would allow users to place guesses whenever they get the lock.这将允许用户在获得锁定时进行猜测。

I changed the List<User> collection to the safer ConcurrentQueue我将List<User>集合更改为更安全的ConcurrentQueue

ConcurrentQueue<User> users = new ConcurrentQueue<User>();

I've initialized the semaphore我已经初始化了信号量

static Semaphore semaphore = new Semaphore(1,Environment.ProcessorCount);

So the method guessWord() looks like this所以 guessWord() 方法看起来像这样

if (users.Count > 0)
            {
           

            while (gameIsPlaying)
            {
                string data = reader.ReadLine();
                //Whatever what writer object print, shows on client side(in putty)
                writer.WriteLine(TakeGuess(user, data));

                if(winner != 0)
                {
                    Console.WriteLine("Number of players in game:" + " " + users.Count);
                    gameIsPlaying = false;
                    Console.WriteLine("Winner is user with id" + " " + winner);
                    writer.WriteLine("Winner is user with id" + " " + winner);
                    users.Clear();
                }

                
                if (Validation(data).Equals(this.Word) )
                {
                    if (winner == 0)
                    {
                      winner = user.Id;

                    }
                    gameIsPlaying = false;
                }
               
             
            }
        
            writer.WriteLine("The game is over");

In method LoopClient() in class Server I've added these 3 lines to "start the traffic light"在类ServerLoopClient()方法中,我添加了这 3 行来“启动交通灯”

                semaphore.WaitOne();
                puzzle.guessWord( writer, reader,users );
                semaphore.Release();
                Console.WriteLine("Now you are out of the game");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM