public class Logger
{
private Queue<Action> queue;
private ManualResetEvent manual;
private Thread logThread;
/// <summary>
/// 指定存储文件的路径
/// </summary>
public static string Path { get; set; }
//私有构造函数,初始化相关对象 使用单例模式
private Logger()
{
queue = new Queue<Action>();
manual = new ManualResetEvent(false);
logThread = new Thread(Process);
logThread.IsBackground = true;
logThread.Start();
}
private readonly static Logger logger = new Logger();
private static Logger GetInstance()
{
return logger;
}
//不断处理队列中的任务
private void Process()
{
while (true)
{
manual.WaitOne();
manual.Reset();
Thread.Sleep(100);
Queue<Action> copy;
lock (queue)
{
copy = new Queue<Action>(queue);
queue.Clear();
foreach (var action in copy)
action();
}
}
}
private void ExcuteAction(string log)
{
string date = DateTime.Now.ToString();
string path;
if (!string.IsNullOrEmpty(Path))
path = Path + "log.txt";
else
path = "log.txt";
lock(queue)
{
queue.Enqueue(() => File.AppendAllText(path, log+" : "+date + Environment.NewLine));
}
manual.Set();
}
/// <summary>
/// 将数据写入文件中
/// </summary>
/// <param name="log">要写入的数据</param>
public static void WriteLog(string log)
{
// WriteLog 方法只是向队列中添加任务,执行时间极短,所以使用Task.Run。
Task.Run(() =>
{
GetInstance().ExcuteAction(log);
});
}
}
两条线程读写同一个对象,两条线程都lock这个对象
用ManualResetEvent来控制读数据的线程(Thread(Process))
当写数据的线程(Task.Run)有数据写入时开启读线程工作
这样有可能控制并发,但测试几次,发现几次数据的顺序有误,但没有漏
主线程和新线程调用第三次后顺序没错
开Task线程调用顺序完全相反,开始两次也会有些乱!!!!!!!!!!!!
调用代码
class Program
{
static void Main(string[] args)
{
//Task.Run(() => TestLogger());
//TestLogger();
new Thread(TestLogger).Start();
Console.ReadKey();
}
static void TestLogger()
{
for (int i = 0; i < 50; i++)
{
Logger.WriteLog(i.ToString());
}
}
}
从队列中取元素的时候不要foreach要出队.放进去的也时候,操作private Queue<Action> queue;对象就好.不要想太多.
人家队列类都给你做好这些东西了.你不用怪谁.
lock (queue)
{
while (queue.Count > 0)
{
var action = queue.Dequeue();
action();
}
}
您的意思是改成这样吧,谢谢指点
不过还是有乱序的问题
把WriteLog中的线程去了
谢谢指点
是的,应该让客户端开线程做写入
Queue换成ConcurrentQueue,其他所有互斥量全部拿掉,就当做单线程处理即可。
另while(true)这种做法不好,相当于你就只考虑开始不考虑结束,如果中途需要停止最好是通过通知的方式传过来。
谢谢指点,我也不喜欢while(true)我就是想试试线程安全和并发,我是业余自学.net的,文化有限,初中毕业,现在人也老了,估计是没希望从事这行了。开始学的还蛮好的,后面越来越觉得要学的太多
@随机哥丶: .net的学习曲线较java而言平滑一些,当然随着了解的深入涉及的东西就会越多,这个是没有办法的。关于多线程,建议先不要看task和并行,直接学thread及threadpool,几种信号量。练手也不要以有外部依赖的东西着手(比如你读写文件,这个实际会使场景变的更复杂),选用普通的cpu密集型计算更简单而且也容易验证些(比如数字的累加)。