为了账号安全,请及时绑定邮箱和手机立即绑定

关于.net线程安全问题

关于.net线程安全问题

largeQ 2018-12-07 09:13:01
public class Logger    {                private Queue queue;        private ManualResetEvent manual;                private Thread logThread;        ///         /// 指定存储文件的路径        ///         public static string Path { get; set; }         //私有构造函数,初始化相关对象 使用单例模式        private Logger()        {            queue = new Queue();            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 copy;                lock (queue)                {                    copy = new Queue(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();        }                 ///         /// 将数据写入文件中        ///         /// 要写入的数据        public static void WriteLog(string log)        {            // WriteLog 方法只是向队列中添加任务,执行时间极短,所以使用Task.Run。            Task.Run(() =>            {                GetInstance().ExcuteAction(log);            });        } }  两条线程读写同一个对象,两条线程都lock这个对象 用ManualResetEvent来控制读数据的线程(Thread(Process)) 当写数据的线程(Task.Run)有数据写入时开启读线程工作 这样有可能控制并发,但测试几次,发现几次数据的顺序有误,但没有漏主线程和新线程调用第三次后顺序没错  开Task线程调用顺序完全相反,开始两次也会有些乱!!!!!!!!!!!!
查看完整描述

7 回答

?
12345678_0001

TA贡献1802条经验 获得超5个赞

从队列中取元素的时候不要foreach要出队.放进去的也时候,操作private Queue queue;对象就好.不要想太多. 人家队列类都给你做好这些东西了.你不用怪谁.
查看完整回答
反对 回复 2018-12-09
?
拉莫斯之舞

TA贡献1820条经验 获得超10个赞

把WriteLog中的线程去了
查看完整回答
反对 回复 2018-12-09
?
慕哥6287543

TA贡献1831条经验 获得超10个赞

谢谢指点
查看完整回答
反对 回复 2018-12-09
?
慕丝7291255

TA贡献1859条经验 获得超6个赞

是的,应该让客户端开线程做写入
查看完整回答
反对 回复 2018-12-09
?
慕桂英546537

TA贡献1848条经验 获得超10个赞

Queue换成ConcurrentQueue,其他所有互斥量全部拿掉,就当做单线程处理即可。 另while(true)这种做法不好,相当于你就只考虑开始不考虑结束,如果中途需要停止最好是通过通知的方式传过来。
查看完整回答
反对 回复 2018-12-09
?
神不在的星期二

TA贡献1963条经验 获得超6个赞

谢谢指点,我也不喜欢while(true)我就是想试试线程安全和并发,我是业余自学.net的,文化有限,初中毕业,现在人也老了,估计是没希望从事这行了。开始学的还蛮好的,后面越来越觉得要学的太多
查看完整回答
反对 回复 2018-12-09
?
芜湖不芜

TA贡献1796条经验 获得超7个赞

@随机哥丶: .net的学习曲线较java而言平滑一些,当然随着了解的深入涉及的东西就会越多,这个是没有办法的。关于多线程,建议先不要看task和并行,直接学thread及threadpool,几种信号量。练手也不要以有外部依赖的东西着手(比如你读写文件,这个实际会使场景变的更复杂),选用普通的cpu密集型计算更简单而且也容易验证些(比如数字的累加)。
查看完整回答
反对 回复 2018-12-09
  • 7 回答
  • 0 关注
  • 377 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信