【问题标题】:how to access list elements in each thread sequentially如何按顺序访问每个线程中的列表元素
【发布时间】:2015-02-16 09:05:56
【问题描述】:

最近在电话面试中被问到这个问题

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

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

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();

        }
    }
}

【问题讨论】:

  • 您的所有线程似乎都在访问您的所有列表——您可能希望将列表设为show 的参数。此外,您可能希望为列表中的每个项目获取/释放信号量,而不是整个列表。
  • 线程执行顺序默认是不可预知的。但是,您可以实现自定义 ThreadPool 来控制它。

标签: c# .net multithreading


【解决方案1】:

信号量本身并不适合您的要求。信号量可以同步对给定资源的访问,但它不维护尝试访问它的线程之间的顺序。每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

【讨论】:

    猜你喜欢
    • 2014-03-03
    • 2023-02-17
    • 2021-07-25
    • 2014-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-24
    • 2014-05-25
    相关资源
    最近更新 更多