在c#上同时在控制台上打印,是否可能?

时间:2015-02-19 21:10:17

标签: c# loops console-application simultaneous

我是编程新手,目前我正在努力学习c#。这是我的问题: 我有以下代码:

static void Main()
    {
        string loading = "LOADING...";
        for (int i = 0; i < 5; i++)
        {
            foreach (var letter in loading)
            {
                Console.Write("{0}", letter);
                Thread.Sleep(250);
            }
            Console.Clear();
            Console.Write("\r");
        }
        for (int k = 0; k <= 100; k++)
        {
            Console.Write("\r{0}%", k);
            Thread.Sleep(150);
        }
    }

我试图找到一种同时执行这两个for循环的方法。我想继续在控制台上重写LOADING并在其下面打印从1到100的百分比。现在第二个for循环在第一次退出后运行。是否有可能让它们同时运行?我一直试图找几个小时的答案,但到目前为止没有运气。 谢谢!

2 个答案:

答案 0 :(得分:1)

正如krillgar所说,你可以使用Tasks独立运行每个循环。像这样:

        string loading = "LOADING...";
        var loadingTask = Task.Run(() =>
        {
            for (int i = 0; i < 5; i++)
            {
                foreach (var letter in loading)
                {
                    Console.Write("{0}", letter);
                    Thread.Sleep(250);
                }
                Console.Clear();
                Console.Write("\r");
            }
        });
        var pocTask = Task.Run(() =>
        {
            for (int k = 0; k <= 100; k++)
            {
                Console.Write("\r{0}%", k);
                Thread.Sleep(150);
            }
        });

        Task.WaitAll(loadingTask, pocTask);

请注意,它不会像你期望的那样工作(第一行有LOADING ......第二行有百分比)。这需要在这些循环之间对显示的消息进行一些同步,我认为这完全是另一个故事而不是你问题答案的范围。

答案 1 :(得分:0)

除了在两个线程中运行代码之外,还有更多挑战。当多个线程同时尝试写入控制台时,您很可能会遇到竞争条件,其中一个线程开始在另一个线程的输出中间写入。

为防止这种情况发生,您需要强制执行关键部分,这些部分是代码中只能有一个线程可以随时执行的区域。这些通常包括:

// Critical section
lock (syncLock)
{
    Console.SetCursorPosition(x, y);
    Console.Write(yourText);
}
Thread.Sleep(yourDelay);

以下是完整代码:

// Dummy object to serve as mutual-exclusion lock when synchronizing threads.
private static readonly object syncLock = new object();

public static void Main(string[] args)
{
    // Run two anonymous functions in parallel,
    // then wait for both to complete.
    Parallel.Invoke(

        // Anonymous function for printing "LOADING..."
        () =>
        {
            const string loading = "LOADING...";
            for (int i = 0; i < 5; i++)
            {
                for (int j = 0; j < loading.Length; j++)
                {
                    // Critical section
                    lock (syncLock)
                    {
                        Console.SetCursorPosition(j, 0);
                        Console.Write("{0}", loading[j]);
                    }
                    Thread.Sleep(250);
                }

                // Critical section
                lock (syncLock)
                {
                    Console.SetCursorPosition(0, 0);
                    Console.Write("\r          ");
                }
                Thread.Sleep(250);
            }
        },

        // Anonymous function for printing "x%"
        () =>
        {
            for (int k = 0; k <= 100; k++)
            {
                // Critical section
                lock (syncLock)
                {
                    Console.SetCursorPosition(0, 1);
                    Console.Write("\r{0}%", k);
                }
                Thread.Sleep(150);
            }
        });
    }
}