使用三个线程访问三个列表,按顺序打印项目

时间:2014-12-11 18:49:02

标签: c# multithreading tpl-dataflow

以下是问题:

  

假设有3个列表l1,l2& l3长度相同。三个线程访问三个列表。说T1 - > l1,T2 - > l2& T3-> l3。它应按顺序打印说明第一个元素,然后是第二个列表的第一个元素,然后是第三个列表的第一个元素。然后是第一个的第二个元素,然后是第二个列表的第二个元素,然后是第三个列表的第二个元素。

我尝试了什么:

 private static readonly Object obj = new Object();
    static List<string> list1 = new List<string> { "1", "2", "3", "4" };
    static List<string> list2 = new List<string> { "a", "b", "c", "d" };
    static List<string> list3 = new List<string> { "*", "+", "-", "?" };
    static int i = 0;
    static void Main(string[] args)
    {
        Thread t1 = new Thread(() => PrintItem());
        t1.Name = "Print1";
        Thread t2 = new Thread(() => PrintItem());
        t2.Name = "Print2";
        Thread t3 = new Thread(() => PrintItem());
        t3.Name = "Print3";
        t1.Start();
        t2.Start();
        t3.Start();
        t1.Join();
        t2.Join();
        t3.Join();
        Console.Read();
    }

    private static void PrintItem()
    {
        while (true)
        {
            lock (obj)
            {
                if (i >= list1.Count)
                    break;
                Console.WriteLine(Thread.CurrentThread.Name + " " + list1[i]);
                Console.WriteLine(Thread.CurrentThread.Name + " " + list2[i]);
                Console.WriteLine(Thread.CurrentThread.Name + " " + list3[i]);
                i++;
            }
        }
    }

输出正确,但它不使用三个线程。请更正代码。

3 个答案:

答案 0 :(得分:2)

虽然这是一个非常奇怪的要求,但可以使用Monitor.PulseMonitor.Wait

    private static readonly Object obj = new Object();
    static List<string> list1 = new List<string> { "1", "2", "3", "4" };
    static List<string> list2 = new List<string> { "a", "b", "c", "d", "e" };
    static List<string> list3 = new List<string> { "*", "+", "-", "?" };
    static int i = 0;

    //thread synchronization data
    const int numThreads = 3;
    static int workingCount = 0;
    static int lastItem = 0;
    static object locker = new object();

    static void Main(string[] args)
    {
        Thread t1 = new Thread(PrintItem);
        t1.Name = "Print1";
        Thread t2 = new Thread(PrintItem);
        t2.Name = "Print2";
        Thread t3 = new Thread(PrintItem);
        t3.Name = "Print3";
        t1.Start(0);
        t2.Start(1);
        t3.Start(2);
        t1.Join();
        t2.Join();
        t3.Join();
        Console.ReadLine();
    }

    private static void PrintItem(object state)
    {
        Interlocked.Increment(ref workingCount);
        int workingList = (int)state;
        int idx = 0;
        List<string> list = null;
        switch (workingList)
        {
            case 0:
                list = list1;
                break;
            case 1:
                list = list2;
                break;
            case 2:
                list = list3;
                break;
        }


        lock (locker)
            do
            {
                while ((lastItem % numThreads) != workingList)
                {
                    Monitor.Wait(locker);
                }

                Console.WriteLine("Thread: {0}\tValue: {1}", Thread.CurrentThread.Name, list[idx]);
                lastItem++;
                Monitor.PulseAll(locker);

            } while (++idx < list.Count);

        //Handle continuing to pulse until all lists are done.
        Interlocked.Decrement(ref workingCount);

        lock (locker)
            while (workingCount != 0)
            {
                while ((lastItem % numThreads) != workingList)
                    Monitor.Wait(locker);
                lastItem++;
                Monitor.PulseAll(locker);
            }

    }
}

enter image description here

答案 1 :(得分:1)

如果是我,我会使用EventWaitHandles来发信号并同步你的线程。在我的代码中,Threads等待一个Signal然后打印出他们当前的字符串然后等待再次发出信号:

    static void Main(string[] args)
    {
        List<string> list1 = new List<string> { "1", "2", "3", "4" };
        List<string> list2 = new List<string> { "a", "b", "c", "d" };
        List<string> list3 = new List<string> { "*", "+", "-", "?" };


        using (EventWaitHandle waitHandle1 = new AutoResetEvent(false))
        using (EventWaitHandle waitHandle2 = new AutoResetEvent(false))
        using (EventWaitHandle waitHandle3 = new AutoResetEvent(false))
        using (EventWaitHandle waitHandle4 = new AutoResetEvent(false))
        {
            Thread t1 = new Thread(() => 
            {
                ThreadData state = new ThreadData() 
                { 
                    Name = "Thread1", 
                    Strings = list1, 
                    WaitHandle = waitHandle1, 
                    SignalHandle = waitHandle2 
                };

                PrintItemWhenSignaled(state);
            });

            Thread t2 = new Thread(() => 
            {
                ThreadData state = new ThreadData()
                {
                    Name = "Thread2",
                    Strings = list2,
                    WaitHandle = waitHandle2,
                    SignalHandle = waitHandle3
                };

                PrintItemWhenSignaled(state);
            });

            Thread t3 = new Thread(() =>
            {
                ThreadData state = new ThreadData()
                {
                    Name = "Thread3",
                    Strings = list3,
                    WaitHandle = waitHandle3,
                    SignalHandle = waitHandle4
                };

                PrintItemWhenSignaled(state);
            });


            t1.Start();
            t2.Start();
            t3.Start();

            for (int index = 0; index < list1.Count; index++)
            {
                waitHandle1.Set();
                waitHandle4.WaitOne(100);
            }
        }

        Console.WriteLine("Press any key...");
        Console.ReadKey();
    }

    private static void PrintItemWhenSignaled(ThreadData threadState)
    {
        foreach (string value in threadState.Strings)
        {
            threadState.WaitHandle.WaitOne(100);
            Console.WriteLine("{0}:{1}", threadState.Name, value);
            threadState.SignalHandle.Set();
        }
    }

    public class ThreadData
    {
        public string Name { get; set; }
        public EventWaitHandle WaitHandle { get; set; }
        public EventWaitHandle SignalHandle { get; set; }
        public List<string> Strings { get; set; }
    }
}

答案 2 :(得分:-1)

因为Lock只有一个线程......第一个是第一个......可以访问你的列表。

删除锁定语句或删除:

        if (i >= list1.Count)
                break;

条件,或者使用属性ThreadStatic

制作i ThreadStatic

如果这是你的预期输出? enter image description here