using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections;
using System.Reflection;
using System.Windows.Forms;
using System.IO;namespace 多线程写入
{
public partial class Form1 : Form
{ private Dictionary<string, string> stcMem = new Dictionary<string, string>();//用于多线程存入数据
//private Hashtable hs = new Hashtable();
//private Hashtable hssync = Hashtable.Synchronized(new Hashtable());
bool canWrite = true;
int threadNum = 0;//已启动的线程条数
ManualResetEvent writeEvent = new ManualResetEvent(true);
int writeNum = 0;//写入数量
int readnum = 0;//从对象读出线程条数 int allNum = 0;//写入数据累加 public Form1()
{
InitializeComponent();
}
/// <summary>
///执行写入操作
/// </summary>
/// <param name="i"></param>
private void m_write(object i)
{ threadNum++; while (true)
{
if (canWrite)//多此一举吗?因为我在计时器里 writeEvent.Reset();并不能阻止写入,所以又加了这个
{
//
}
else
{
writeEvent.Reset();
} writeEvent.WaitOne();//这个好象并不能锁住写放啊???????到一定时间,阻塞就会失败!!!!!!为什么,就会报“集合已修改;可能无法执行枚举操作。这里老是会出这个错误” 请高手解
stcMem.Add(Guid.NewGuid().ToString(), "valuevaluevaluevaluevaluevaluevaluevaluevaluevaluevalue");
//hssync.Add(Guid.NewGuid().ToString(), "valuevaluevaluevaluevaluevaluevaluevaluevaluevaluevalue");
writeNum++;
Thread.Sleep(100); }
} private void timerShow_Tick(object sender, EventArgs e)
{
lbNum.Text = "线程数:" + threadNum + " 执行写入:" + writeNum.ToString() + " 实际效果:" + allNum + "当前条数:" + stcMem.Count + " 读取" + readnum + "次";
//lbNum.Text = "线程数:" + threadNum + " 执行写入:" + writeNum.ToString() + " 实际效果:" + hssync.Count; } private void button1_Click(object sender, EventArgs e)
{ for (int i = 0; i < 100; i++)//创建100个线程进行不段的写入操作
{
ThreadPool.QueueUserWorkItem(new WaitCallback(m_write), i); }
} private void button2_Click(object sender, EventArgs e)
{
canWrite = false;
writeEvent.Reset();//停止写入
} private void timerSave_Tick(object sender, EventArgs e)
{
canWrite = false;
writeEvent.Reset();
System.Text.StringBuilder sb = new StringBuilder();
foreach (var i in stcMem)//集合已修改;可能无法执行枚举操作。这里老是会出这个错误
{
string val = i.Value;
if (!string.IsNullOrEmpty(val))
sb.Append(i.Value.ToString() + "\n");
}
allNum += stcMem.Count;
stcMem.Clear();
string filename = @"savefiles/" + Guid.NewGuid().ToString() + "_" + readnum + ".txt";
string willstr = sb.ToString();
if (willstr != "")
{
File.WriteAllText(filename, willstr);
}
readnum++; //IDictionaryEnumerator myEnumerator = hssync .GetEnumerator();
//while (myEnumerator.MoveNext())
//{
// string val = myEnumerator.Value.ToString();
//}
canWrite = true;
writeEvent.Set();
}
}
}
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections;
using System.Reflection;
using System.Windows.Forms;
using System.IO;namespace 多线程写入
{
public partial class Form1 : Form
{ private Dictionary<string, string> stcMem = new Dictionary<string, string>();//用于多线程存入数据
//private Hashtable hs = new Hashtable();
//private Hashtable hssync = Hashtable.Synchronized(new Hashtable());
bool canWrite = true;
int threadNum = 0;//已启动的线程条数
ManualResetEvent writeEvent = new ManualResetEvent(true);
int writeNum = 0;//写入数量
int readnum = 0;//从对象读出线程条数 int allNum = 0;//写入数据累加 public Form1()
{
InitializeComponent();
}
/// <summary>
///执行写入操作
/// </summary>
/// <param name="i"></param>
private void m_write(object i)
{ threadNum++; while (true)
{
if (canWrite)//多此一举吗?因为我在计时器里 writeEvent.Reset();并不能阻止写入,所以又加了这个
{
//
}
else
{
writeEvent.Reset();
} writeEvent.WaitOne();//这个好象并不能锁住写放啊???????到一定时间,阻塞就会失败!!!!!!为什么,就会报“集合已修改;可能无法执行枚举操作。这里老是会出这个错误” 请高手解
stcMem.Add(Guid.NewGuid().ToString(), "valuevaluevaluevaluevaluevaluevaluevaluevaluevaluevalue");
//hssync.Add(Guid.NewGuid().ToString(), "valuevaluevaluevaluevaluevaluevaluevaluevaluevaluevalue");
writeNum++;
Thread.Sleep(100); }
} private void timerShow_Tick(object sender, EventArgs e)
{
lbNum.Text = "线程数:" + threadNum + " 执行写入:" + writeNum.ToString() + " 实际效果:" + allNum + "当前条数:" + stcMem.Count + " 读取" + readnum + "次";
//lbNum.Text = "线程数:" + threadNum + " 执行写入:" + writeNum.ToString() + " 实际效果:" + hssync.Count; } private void button1_Click(object sender, EventArgs e)
{ for (int i = 0; i < 100; i++)//创建100个线程进行不段的写入操作
{
ThreadPool.QueueUserWorkItem(new WaitCallback(m_write), i); }
} private void button2_Click(object sender, EventArgs e)
{
canWrite = false;
writeEvent.Reset();//停止写入
} private void timerSave_Tick(object sender, EventArgs e)
{
canWrite = false;
writeEvent.Reset();
System.Text.StringBuilder sb = new StringBuilder();
foreach (var i in stcMem)//集合已修改;可能无法执行枚举操作。这里老是会出这个错误
{
string val = i.Value;
if (!string.IsNullOrEmpty(val))
sb.Append(i.Value.ToString() + "\n");
}
allNum += stcMem.Count;
stcMem.Clear();
string filename = @"savefiles/" + Guid.NewGuid().ToString() + "_" + readnum + ".txt";
string willstr = sb.ToString();
if (willstr != "")
{
File.WriteAllText(filename, willstr);
}
readnum++; //IDictionaryEnumerator myEnumerator = hssync .GetEnumerator();
//while (myEnumerator.MoveNext())
//{
// string val = myEnumerator.Value.ToString();
//}
canWrite = true;
writeEvent.Set();
}
}
}
{ threadNum++; while (true)
{
lock(stcMem){
stcMem.Add(Guid.NewGuid().ToString(), "valuevaluevaluevaluevaluevaluevaluevaluevaluevaluevalue");
//hssync.Add(Guid.NewGuid().ToString(), "valuevaluevaluevaluevaluevaluevaluevaluevaluevaluevalue");
writeNum++;
}
Thread.Sleep(100); }
}private void timerSave_Tick(object sender, EventArgs e)
{
System.Text.StringBuilder sb = new StringBuilder();
lock(stcMem)
{
foreach (var i in stcMem)//集合已修改;可能无法执行枚举操作。这里老是会出这个错误
{
string val = i.Value;
if (!string.IsNullOrEmpty(val))
sb.Append(i.Value.ToString() + "\n");
}
allNum += stcMem.Count;
stcMem.Clear();
}
string filename = @"savefiles/" + Guid.NewGuid().ToString() + "_" + readnum + ".txt";
string willstr = sb.ToString();
if (willstr != "")
{
File.WriteAllText(filename, willstr);
}
readnum++; //IDictionaryEnumerator myEnumerator = hssync .GetEnumerator();
//while (myEnumerator.MoveNext())
//{
// string val = myEnumerator.Value.ToString();
//}
canWrite = true;
writeEvent.Set();
}
}
我想实现的是,平常情况下,高效的多线程并发写入,在读取dictionary时,才暂时阻止所有线程写入,一旦读完,马上重新允许写入
上面的程序在线程数不大的情况下(50-60个写入线程),执行段时间就会出现“集合已修改;可能无法执行枚举操作。”,我也想用for ,便那样,是边读边写,数据会不数据会不符合要求,请高手解答!谢谢
如果你调用writeEvent.ReSet()的时候有的线程已经越过了writeEvent.WaitOne(),将要或者正在执行stcMem.Add(),那么就很有可能在你获得了迭代器之后会因为stcMem.Add()的执行导致集合状态改变。
也就是说你仅仅向写入方发出了暂停写入的请求,但是没有等待已经开始的写入完成。换成ConcurrentDictionary可以解决这个问题——它的迭代器本身就是可以安全同步读写的,writeEvent这些都可以省掉。
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;namespace WindowsFormsApplication5
{
public partial class Form1 : Form
{
private ReaderWriterLockSlim _ReadWriteLock;
private Dictionary<string, string> stcMem = new Dictionary<string, string>(1000000);//用于多线程存入数据 public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
_ReadWriteLock = new ReaderWriterLockSlim();
} private void WriteThread(Object obj)
{
_ReadWriteLock.EnterWriteLock();
try
{
for (Int32 i = 0; i < 10000; i++)
{
stcMem.Add(Guid.NewGuid().ToString(), Guid.NewGuid().ToString());
}
}
finally
{
_ReadWriteLock.ExitWriteLock();
}
} private void ReadThread(Object obj)
{
_ReadWriteLock.EnterReadLock();
try
{
foreach (KeyValuePair<String, String> item in stcMem)
{
listBox1.Items.Add(item.Key + " " + item.Value);
}
}
finally
{
_ReadWriteLock.ExitReadLock();
}
} private void button1_Click(object sender, EventArgs e)
{
for (Int32 i = 0; i < 10; i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(WriteThread), null);
}
} private void button2_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ReadThread), null);
} }
}