Home > Mobile >  How to synchronize threads so that they respond to user input?
How to synchronize threads so that they respond to user input?

Time:12-18

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. If he guesses the word, he wins. Multiple players/users can join the game(Later I will limit to a reasonable number, like 3). Client connects via putty

In this task I need to use multiple threads and then synchronize them somehow. Let's take into account that there are 3 players playing. 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? I used Join, but I don't know if it accomplishes what I want

b)Is this style of play(Waiting for players to next guess) at all good for the example with thread work?

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)

CodePudding user response:

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>. 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). 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. 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.

  • Related