我想添加/删除列表,但出现“索引超出范围”异常。在我的代码中,我每秒添加2次数据直到10。然后通过使用线程将其删除。我也使用信号量进行阻止。我想同时使用3个线程。
这是我的代码
class Program
{
private static Thread[] threads = new Thread[3];
private static Semaphore sem = new Semaphore(3, 3);
private static List<string> messagesList = new List<string>();
private static readonly object _kilit = new object();
static void Main(string[] args)
{
Thread addData = new Thread(AddData);
addData.Start();
for (int j = 0; j < 3; j++)
{
threads[j] = new Thread(AddComma);
threads[j].Name = "thread_" + j;
threads[j].Start();
}
}
public static void AddData()
{
for (int i = 0; i < 10; i++)
{
messagesList.Add("data");
messagesList.Add("data");
Thread.Sleep(1000);
}
}
public static void AddComma()
{
sem.WaitOne();
while (true) {
if (messagesList.Count > 0)
{
Console.WriteLine();
Console.WriteLine(Thread.CurrentThread.Name + "Entering to Critical section");
int averageIndex = messagesList[0].ToString().Length / 2; // Here is the error
string msg = messagesList[0].ToString().Substring(0, averageIndex) + "," + messagesList[0].ToString().Substring(averageIndex);
Console.WriteLine(msg);
messagesList.RemoveAt(0);
Console.WriteLine(Thread.CurrentThread.Name + "Exiting from Critical Section");
}
}
sem.Release();
}
}
答案 0 :(得分:3)
您允许三个线程同时运行:
new Semaphore(3, 3);
因此您的Semaphore
并没有真正帮助您,因为您并未真正阻止。因此,您仍然遇到问题,例如,列表中可能剩下一条消息,但是3个线程都将messagesList.Count > 0
评估为true
。这些线程之一将首先从列表中删除该项目,这将导致其他两个抛出异常。
有更好的方法可以做到这一点。对于列表,我喜欢使用具有读锁和写锁的ReaderWriterLockSlim
。它允许所有线程读取,但在您获得写锁后将阻止所有人。在文档中有一个如何使用它的示例。
答案 1 :(得分:2)
问题1:您允许3个并发线程访问列表,应为new Semaphore(1,1);
问题2:永远不会调用sem.Release()(由于while(true)而导致无法访问的代码),因此您必须将sem.WaitOne()移到第一个语句中,而将block和sem.Release()移到第一个语句中while块内的最后一行
工作代码:
class Program
{
private static Thread[] threads = new Thread[3];
private static Semaphore sem = new Semaphore(1, 1);
private static List<string> messagesList = new List<string>();
private static readonly object _kilit = new object();
static void Main(string[] args)
{
Thread addData = new Thread(AddData);
addData.Start();
for (int j = 0; j < 3; j++)
{
threads[j] = new Thread(AddComma);
threads[j].Name = "thread_" + j;
threads[j].Start();
}
}
public static void AddData()
{
for (int i = 0; i < 10; i++)
{
messagesList.Add("data");
messagesList.Add("data");
Thread.Sleep(1000);
}
}
public static void AddComma()
{
while (true)
{
sem.WaitOne();
if (messagesList.Count > 0)
{
Console.WriteLine();
Console.WriteLine(Thread.CurrentThread.Name + "Entering to Critical section");
int averageIndex = messagesList[0].ToString().Length / 2; // Here is the error
string msg = messagesList[0].ToString().Substring(0, averageIndex) + "," + messagesList[0].ToString().Substring(averageIndex);
Console.WriteLine(msg);
messagesList.RemoveAt(0);
Console.WriteLine(Thread.CurrentThread.Name + "Exiting from Critical Section");
}
sem.Release();
}
}
}