最近我在电话采访中被问到这个问题
“假设有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();
}
}
}
答案 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