如何在一个线程中做几次直到成功?

时间:2017-06-22 09:30:42

标签: c# .net multithreading parallel-processing

我希望每个玩家都有一个线程来猜测一个数字。 但现在我每次创建一个线程并获得内存不足异常。 怎么解决?如何让一个线程猜数字直到获胜。 我想拥有与玩家一样多的线程并执行该功能直到有人获胜。

  static void Main(string[] args)
    {
        object lockObject = new object();
        bool isGameOver = false;

        int weightOfBasket = Game.SetWeightForBasket();
        Console.WriteLine("Real weight : " + weightOfBasket);

        Console.WriteLine("Count of players in this game?");
        var countOfPlayers = Convert.ToInt32(Console.ReadLine());

        var players = new List<IPlayer>();
        for (int i = 0; i < countOfPlayers; i++)
        {
            IPlayer player = null;
            Console.WriteLine("Player's name:");
            string playerName = Console.ReadLine();
            Console.WriteLine("Player's type:");
            string playerType = Console.ReadLine();
            bool isExist = playerType != null && Enum.IsDefined(typeof(Game.Type), value: playerType);
            if (isExist)
            {
                Type type = Type.GetType("TestTask_game." + playerType + "Player");
                if (type != null)
                {
                    player = (IPlayer)Activator.CreateInstance(type);
                }
                if (player != null)
                {
                    player.Name = playerName;
                    player.Type = playerType;
                    players.Add(player);
                }
            }
        }
        while (!isGameOver)
        {
            Parallel.ForEach(players, new ParallelOptions(),
                (player, i, j) =>
                {
                    ThreadPool.QueueUserWorkItem(o => TryToGuess(player, weightOfBasket, out isGameOver, ref lockObject));
                });
        }
        FindClosestToWinPlayer(players, weightOfBasket);
        Console.ReadLine();
    }

 private static void TryToGuess(IPlayer player, int weightOfBasket, out bool IsWinner, ref object objectToLock)
    {
        lock (objectToLock)
        {
            if (_overallAmountOfAttempts == Game.AttemptsLimit)
            {
                IsWinner = true;
                Thread.CurrentThread.Join();
                return;
            }
            _overallAmountOfAttempts++;

            int numberToGuess = player.GetNumberToGuess();
            Game.AllNumberAttempts.Add(numberToGuess);

            Console.WriteLine("Number is " + numberToGuess + "?");
            Console.WriteLine("Attempt was made by " + player.Name);

            if (numberToGuess == weightOfBasket)
            {
                Console.WriteLine(player.Name + " is a winner. Count of attempts = " + player.CountOfAttempts);
                IsWinner = true;
                Thread.CurrentThread.Join();
            }
            else
            {
                int delta = weightOfBasket - numberToGuess;
                Thread.Sleep(Math.Abs(delta) * 1000);
                IsWinner = false;
            }
            Console.WriteLine(_overallAmountOfAttempts);
        }
    }

1 个答案:

答案 0 :(得分:1)

您需要仔细考虑多线程是否是您需要的,大部分时间都不是。这是一个相当复杂的主题,在最好的时候很难做到。

在你的while循环中你几乎不断地创建新线程,据我所知,在while循环期间条件永远不会变为false。此外,您在同一个对象上锁定了TryToGuess函数,这使得多线程无论如何都是无意义的 - 一次只有一个线程会进入锁定。

如果你真的确定你必须有多线程,那么这里更好的方法是为每个玩家只创建一次线程,然后让它们运行完成并在它们运行时同步它们。此外,使用Tasks或其他更高级别的抽象而不是手动处理多线程。

编辑:无论如何这一切似乎都是一个高度连续的过程 - 玩家轮流,只有一个控制台......这就是为什么我说多线程可能不是正确的方法。

编辑编辑:但是如果你真的真的想要使用多线程,我想,为了好玩或学习,你必须考虑到玩家线程和主线程之间需要进行大量的通信。他们需要知道轮到他们的时候,他们需要回答玩家是否赢了。因此,我能想到的一个合理方法是为每个玩家设置信号量,并在玩家轮到时发出信号,然后该线程运行,然后主线程检查一些共享状态以查看是否应停止(在每个玩家之后)或者在一个转弯之后),这意味着主线程需要等到玩家线程完成一个转弯。我真的没有看到不会破坏多线程目的的替代方案,抱歉:)