using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp
{
class Program
{
//static AutoResetEvent mre = new AutoResetEvent(true);
static ManualResetEventSlim mre = new ManualResetEventSlim(true);
static List<string> list = new List<string>();
static void Main(string[] args)
{
Task[] tasks = new Task[10000];
for (int i = 0; i < 10000; i++)
{
tasks[i] = Task.Factory.StartNew(Test);
//tasks[i].ContinueWith(t => Set());
}
Task.WaitAll(tasks);
var q = from t in list
group t by t into g
where g.Count() >1
select new
{
g.Key,
Count = g.Count()
};
q.ToList().ForEach((t) => Console.WriteLine(t.Key + "---" + t.Count));
Console.WriteLine("OK");
}
//static void Set()
//{
// mre.Set();
//}
static int n = 0;
static string Test()
{
try
{
mre.Wait();
mre.Reset();
Interlocked.Increment(ref n);
var s = n.ToString();
list.Add(s);
return s;
}
finally
{
mre.Set();
}
}
}
}
List<T> 线程不安全 换成BlockingCollection<T>再试试
不是这个问题,代码里面的是
mre.Wait();和
mre.Reset()不起作用,
理论上Wait是获取互斥对象,Reset()是独占对象, Set()后是释放对象。
感觉是mre.Wait()和mre.Reset()这两句话有问题,可能同时有多个线程Wait()通过。
Wait()运行后Cpu时间片到期,还没有Reset(),这时另外一个线程又Wait()通过。所以锁不了线程。
这样的话ManualResetEventSlim 的正确写法应该怎么写呢
@徐某人:
你是想验证ManualResetEventSlim锁线程?
如果是的话,你的代码里有很多问题
1 验证多线程同步的时候,不要用 Interlocked.Increment(ref n),请用普通的n++ 。
Interlocked.Increment(ref n) 这个方法本身就是有原子性的,每次加算n的时候会阻塞其他进程,所以无论你用不用ManualResetEventSlim,理论上list里的n不可能重复
2 那么问题来了,为啥会出现你提问的现象。原因是ManualResetEventSlim没锁住进程,List线程不安全。而且你还会发现,List里的个数还可能并不等于10000
3 根据上面说的, Interlocked.Increment(ref n) 该成 n++, List改成BlockingCollection, 其他不动,再次执行程序, 会得到什么结果呢 ? List的个数等于10000了, 但是还是可能有重复的。我猜这个才是你想要的验证
4 回到你的问题, 为啥ManualResetEventSlim没锁住进程, 原因就是你自己感觉的一样, mre.Set() 到mre.ReSet()之间,你无法控制有几个进程通过了mre.Wait()。
5 想锁住进程(同一时间只有1个线程执行)怎么办? 请用Lock
6 根据上面你的回复,感觉你对ManualResetEventSlim的理解有问题,ManualResetEventSlim不是锁线程(同一时间只有1个线程执行)用的,是用来做线程等待和同步的
7 关于ManualResetEventSlim和Lock的区别 给你个参考网站
https://www.codeproject.com/Articles/1114506/Thread-Synchronization-Lock-ManualResetEvent-AutoR
ManualResetEventSlim还没用过,但是用过ManualResetEvent,别的我就不多说了,就是创建ManualResetEvent实例的时候传false,就达到了我想要的效果。这个ManualResetEventSlim也可以试试 new ManualResetEventSlim(false)