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

C# 如何按顺序访问每个线程中的列表元素,c#,.net,multithreading,C#,.net,Multithreading,最近我在一次电话采访中被问到这个问题 假设有3个长度相同的数组列表l1、l2和l3。 三个线程访问三个列表。 说T1->l1,T2->l2和T3->l3。 它应该按如下顺序打印:第一个列表的第一个元素,第二个列表的第一个元素,第三个列表的第一个元素。 然后是第一个列表的第二个元素,然后是第二个列表的第二个元素,然后是第三个列表的第二个元素。” 我回答说使用信号量可以解决这个问题,但是当我尝试使用信号量时,却没有得到正确的答案。 我下面的代码有什么问题 namespace Semaphore_Ex

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

假设有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();

        }
    }
}
名称空间信号量\u示例
{
班级计划
{
静态列表list1=新列表{1,2,3,4,5};
静态列表list2=新列表{1,2,3,4,5};
静态列表list3=新列表{1,2,3,4,5};
静态信号量信号量=新信号量(0,3);
静态信号量lim _sem=新信号量lim(3);
静态void Main(字符串[]参数)
{
螺纹t1=新螺纹(显示);
螺纹t2=新螺纹(显示);
螺纹t3=新螺纹(显示);
t1.Start();
t2.Start();
t3.Start();
Console.ReadLine();
}
静态void show()
{
_sem.Wait();
对于(int i=0;i<5;i++)
{
Console.WriteLine(列表1[i]);
Console.WriteLine(列表2[i]);
Console.WriteLine(列表3[i]);
}
_sem.Release();
}
}
}

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

没有保证顺序,例如FIFO或LIFO,其中阻塞线程进入信号量

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

静态列表list1=新列表{“A1”、“A2”、“A3”、“A4”、“A5”};
静态列表list2=新列表{“B1”、“B2”、“B3”、“B4”、“B5”};
静态列表list3=新列表{“C1”、“C2”、“C3”、“C4”、“C5”};
//将所有列表添加到下面的数组中。
静态列表[]列表=新的[]{list1,list2,list3};
静态自动resetEvent[]waitHandles;
静态void Main(字符串[]参数)
{
waitHandles=new AutoResetEvent[lists.Length];
var threads=新线程[lists.Length];
for(int i=0;ishow(threadIndex));
线程[i].Start();
}
//向第一个线程发送信号以启动进程。
waitHandles[0]。Set();
Console.ReadLine();
}
//方法在每个线程中运行。
静态无效显示(int-threadIndex)
{
//打印每个元素后要发送信号的下一个线程的索引。
int-nextThreadIndex=(threadIndex+1)%lists.Length;
//迭代当前线程列表的所有元素。
foreach(列表[threadIndex]中的字符串x)
{
//等待当前线程的轮次。
waitHandles[threadIndex].WaitOne();
//打印一个元素。
控制台。写入(x+“”);
//通知下一个线程继续。
waitHandles[nextThreadIndex].Set();
}
//假设所有列表长度相等。
//否则,线程可能需要保持信令
//甚至在打印完所有元素之后。
}
//输出:A1 B1 C1 A2 B2 C2 A3 B3 C3 A4 B4 C4 A5 B5 C5

您的所有线程似乎都在访问您的所有列表-您可能希望将列表设置为
show
的参数。另外,您可能希望获取/释放列表中每个项目的信号量,而不是整个列表的信号量。默认情况下,线程执行顺序是不可预测的。但是,您可以实现一个自定义线程池来控制它。
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