如何按顺序访问每个线程中的列表元素

时间:2015-02-15 09:36:11

标签: c# .net multithreading

最近我在电话采访中被问到这个问题

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

我回答说使用信号量可以解决这个问题,但是当我尝试使用信号量时,无法得到正确的答案。 我的下面的代码有什么问题

namespace Semaphore_Example
{
    class Program
    {
        static List<int> list1 = new List<int>{ 1, 2, 3, 4, 5 };
        static List<int> list2 = new List<int> { 1, 2, 3, 4, 5 };
        static List<int> list3 = new List<int> { 1, 2, 3, 4, 5 };

        static Semaphore semaphore = new Semaphore(0,3);
        static SemaphoreSlim _sem = new SemaphoreSlim(3);    

        static void Main(string[] args)
        {

            Thread t1 = new Thread(show);
            Thread t2 = new Thread(show);
            Thread t3 = new Thread(show);

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

            Console.ReadLine();
        }

        static void show()
        {
            _sem.Wait();

            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine(list1[i]);
                Console.WriteLine(list2[i]);
                Console.WriteLine(list3[i]);
            }

            _sem.Release();

        }
    }
}

1 个答案:

答案 0 :(得分:7)

信号量本身不适合您的要求。信号量可以同步对给定资源的访问,但它不会在尝试访问它的线程之间维护顺序。每MSDN

  

没有保证订单,例如FIFO或LIFO,其中被阻止的线程进入信号量。

相反,我建议您使用一组等待句柄,每个线程一个,这样每个线程在打印每个元素之前等待它自己的句柄,并在这样做之后发出下一个线程句柄的信号。下面的示例被推广为可以使用任意数量的列表(线程)。

static List<string> list1 = new List<string> { "A1", "A2", "A3", "A4", "A5" };
static List<string> list2 = new List<string> { "B1", "B2", "B3", "B4", "B5" };
static List<string> list3 = new List<string> { "C1", "C2", "C3", "C4", "C5" };

// Add all lists to the array below.
static List<string>[] lists = new[] { list1, list2, list3 };
static AutoResetEvent[] waitHandles;

static void Main(string[] args)
{
    waitHandles = new AutoResetEvent[lists.Length];
    var threads = new Thread[lists.Length];

    for (int i = 0; i < lists.Length; i++)
    {
        // Initialize a wait handle and thread for each list.
        int threadIndex = i;
        waitHandles[i] = new AutoResetEvent(false);
        threads[i] = new Thread(new ThreadStart(() => show(threadIndex)));
        threads[i].Start();
    }

    // Signal first thread to start off process.
    waitHandles[0].Set();

    Console.ReadLine();
}

// Method run within each thread.
static void show(int threadIndex)
{
    // The index of the next thread to signal after printing each element.
    int nextThreadIndex = (threadIndex + 1) % lists.Length;

    // Iterate over all elements of current thread's list.
    foreach (string x in lists[threadIndex])
    {
        // Wait for turn of current thread.
        waitHandles[threadIndex].WaitOne();

        // Print one element.
        Console.Write(x + " ");

        // Signal next thread to proceed.
        waitHandles[nextThreadIndex].Set();
    }

    // Assume all lists are equal in length.
    // Otherwise, threads might need to keep signalling
    // even after printing all their elements.
}

// Output: A1 B1 C1 A2 B2 C2 A3 B3 C3 A4 B4 C4 A5 B5 C5