代码如下:
Thread thd1, thd2;
        
        private void writetxt(string strnr)
        {
            string Sendpath = Application.StartupPath + "\\" + "Send_log.txt";
            lock (this)
            {           
                FileStream FSSend = new FileStream(Sendpath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
                StreamWriter sw = new StreamWriter(FSSend);                 
                sw.WriteLine(strnr);
                sw.Close();
            }
        }        private void thdrun1()
        {
            DateTime currentTime = new DateTime();            while (true)
            {
                currentTime = DateTime.Now;
                string strtime = currentTime.ToString("yyyy-MM-dd HH:mm:ss:fff");
                string strnr = "thd1write: " +strtime;
                writetxt(strnr);
            }
        }        private void thdrun2()
        {
            DateTime currentTime = new DateTime();            while (true)
            {
                currentTime = DateTime.Now;
                string strtime = currentTime.ToString("yyyy-MM-dd HH:mm:ss:fff");
                string strnr = "thd2write: " +strtime;
                writetxt(strnr);
            }
        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            thd1 = new Thread(new ThreadStart(thdrun1));
            thd2 = new Thread(new ThreadStart(thdrun2));
            thd1.Start();
            thd2.Start();
            
        }
上面的程序执行后,在日志文件Send_log.txt里会找到thd1write与thd2write在同一时间里写入的记录,这是怎么回事儿啊?我加了锁了呀,在某一时间段里不能同时有两个进程写日志的啊,什么原因????????

解决方案 »

  1.   

    楼上的,我精确到七位,还是不行啊,如 string strtime = currentTime.ToString("yyyy-MM-dd HH:mm:ss:fffffff");这样还是不行,还有时间重合
      

  2.   

    你精确到7位没有用,因为返回值没有这么精确。
    DateTime.Now的返回值只能精确到1%秒。
      

  3.   

    两个进程么?那要用进程互斥Mutex 
      

  4.   

    Windows的API函数 QueryPerformanceCounter和QueryPerformanceFrequecy       /// <summary>
           /// 获取2个时间点的时间中CPU运行的次数
            /// </summary>
            [DllImport("Kernel32.dll")]
            private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);       /// <summary>
           /// 获取CPU频率
            /// </summary>
            [DllImport("Kernel32.dll")]
            private static extern bool QueryPerformanceFrequency(out long lpFrequency); lpFrequency);
    这两个函数可以精确计时,但是有一部分操作系统不支持,如win98等。而且程序自己运行要消耗一部分时间,可能会影响结果。就上面这个问题是肯定是正常的,不可能会同时写入的。
      

  5.   

    修改成下面这样
    FileStream FSSend = new FileStream(Sendpath, FileMode.Append, FileAccess.Write, FileShare.None);
      

  6.   

    while (true)
      {
      currentTime = DateTime.Now;
      string strtime = currentTime.ToString("yyyy-MM-dd HH:mm:ss:fff");
      string strnr = string.Format("thd2write: [{0}][{1}]",strtime, Enviroment.TickCount); //这句改成这样,你看看最后的数字一不一样  writetxt(strnr);
      }
      

  7.   

    楼上的这个Environment没有定义呀,是不是要引用什么啊?
      

  8.   

    我仰天长叹,CSDN竟无人能答我的问题!可叹,可叹!
      

  9.   


    FileShare.None:谢绝共享当前文件。文件关闭前,打开该文件的任何请求(由此进程或另一进程发出的请求)都将失败。我已经测试过,没设置为None时确实有重复的,设置为None后,不会有重复的了
      

  10.   

    楼上的,你真测试了吗?
    thd1write: 2010-09-21 14:56:38:906
    thd2write: 2010-09-21 14:56:38:906
    thd2write: 2010-09-21 14:56:39:000
    thd2write: 2010-09-21 14:56:39:000
    thd2write: 2010-09-21 14:56:39:000
    thd2write: 2010-09-21 14:56:39:000
    thd2write: 2010-09-21 14:56:39:015
    thd2write: 2010-09-21 14:56:39:015
    thd2write: 2010-09-21 14:56:39:015
    thd2write: 2010-09-21 14:56:39:015
    thd2write: 2010-09-21 14:56:39:015
    thd1write: 2010-09-21 14:56:39:000
    thd1write: 2010-09-21 14:56:39:015
    thd1write: 2010-09-21 14:56:39:015
    thd1write: 2010-09-21 14:56:39:015
    thd1write: 2010-09-21 14:56:39:015
    thd1write: 2010-09-21 14:56:39:031
    thd1write: 2010-09-21 14:56:39:031
    thd2write: 2010-09-21 14:56:39:015
    thd2write: 2010-09-21 14:56:39:031
    thd2write: 2010-09-21 14:56:39:031
    thd2write: 2010-09-21 14:56:39:031
    thd2write: 2010-09-21 14:56:39:031
    thd2write: 2010-09-21 14:56:39:046
    thd2write: 2010-09-21 14:56:39:046
    thd2write: 2010-09-21 14:56:39:046
    thd2write: 2010-09-21 14:56:39:046
    thd2write: 2010-09-21 14:56:39:046
    thd2write: 2010-09-21 14:56:39:046
    thd1write: 2010-09-21 14:56:39:031
    thd1write: 2010-09-21 14:56:39:046
    thd1write: 2010-09-21 14:56:39:046
    thd1write: 2010-09-21 14:56:39:062
    thd1write: 2010-09-21 14:56:39:062
    thd1write: 2010-09-21 14:56:39:062
    thd1write: 2010-09-21 14:56:39:078
    thd1write: 2010-09-21 14:56:39:078
    thd2write: 2010-09-21 14:56:39:046
    thd2write: 2010-09-21 14:56:39:078
    thd2write: 2010-09-21 14:56:39:078
    thd2write: 2010-09-21 14:56:39:078
    thd2write: 2010-09-21 14:56:39:078
    thd2write: 2010-09-21 14:56:39:093
    thd1write: 2010-09-21 14:56:39:078
    thd2write: 2010-09-21 14:56:39:093
    thd2write: 2010-09-21 14:56:39:093
    thd2write: 2010-09-21 14:56:39:093
    thd2write: 2010-09-21 14:56:39:093
    thd2write: 2010-09-21 14:56:39:093
    thd2write: 2010-09-21 14:56:39:093
    thd1write: 2010-09-21 14:56:39:093
    thd1write: 2010-09-21 14:56:39:109
    thd1write: 2010-09-21 14:56:39:109
    thd1write: 2010-09-21 14:56:39:109
    thd1write: 2010-09-21 14:56:39:109
    thd1write: 2010-09-21 14:56:39:109
    thd1write: 2010-09-21 14:56:39:109这是我测试的,即共享改为None时的结果,怎么没有重复的呢?
      

  11.   

    你这样子同时运行两个线程 没有一点延时,也没有sleep
    就目前的精确度来说 相同也是正常的
      

  12.   


    如果设置为FileShare.None,真的时同时操作文件,肯定会报错的,现在没有报错,就说明没有同时,问题还是出现时间精确度上
      

  13.   

    你的线程 里用额while(Timer定时器回根据时间去循环,) 进行死循环去操作
    中间没有一点间隔时间去循环去操作currentTime  还是建议把currentTime加锁 做成线程同步的
      

  14.   


    不错,真是因为这个原因        Thread thd1, thd2;        private void writetxt(int index)
            {
                string Sendpath = Application.StartupPath + "\\" + "Send_log.txt";
                lock (this)
                {
                    string strtime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff");
                    string strnr = "thd" + index.ToString() + "write: " + strtime;                FileStream FSSend = new FileStream(Sendpath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
                    StreamWriter sw = new StreamWriter(FSSend);
                    sw.WriteLine(strnr);
                    sw.Close();
                }
            }        private void thdrun1()
            {
                while (true)
                {
                    writetxt(1);
                }
            }        private void thdrun2()
            {
                while (true)
                {
                    writetxt(2);
                }
            }        private void button1_Click(object sender, EventArgs e)
            {
                thd1 = new Thread(new ThreadStart(thdrun1));
                thd2 = new Thread(new ThreadStart(thdrun2));
                thd1.Start();
                thd2.Start();        }
      

  15.   

    把时间放到lock (this)里面去
      

  16.   

    thd2write: 2010-09-21 15:24:10:687
    thd1write: 2010-09-21 15:24:10:687
    thd1write: 2010-09-21 15:24:10:687
    thd1write: 2010-09-21 15:24:10:687
    thd1write: 2010-09-21 15:24:10:687
    thd1write: 2010-09-21 15:24:10:687
    thd1write: 2010-09-21 15:24:10:687
    thd1write: 2010-09-21 15:24:10:703
    thd1write: 2010-09-21 15:24:10:703
    thd2write: 2010-09-21 15:24:10:703
    thd2write: 2010-09-21 15:24:10:703
    thd2write: 2010-09-21 15:24:10:703
    thd2write: 2010-09-21 15:24:10:703
    thd2write: 2010-09-21 15:24:10:703
    thd2write: 2010-09-21 15:24:10:703
    thd2write: 2010-09-21 15:24:10:718
    thd2write: 2010-09-21 15:24:10:718
    thd2write: 2010-09-21 15:24:10:718
    thd2write: 2010-09-21 15:24:10:718
    thd1write: 2010-09-21 15:24:10:718
    thd1write: 2010-09-21 15:24:10:718
    thd1write: 2010-09-21 15:24:10:718
    thd1write: 2010-09-21 15:24:10:718
    thd1write: 2010-09-21 15:24:10:718刚才我又试了一遍,不行的
      

  17.   

    用29楼的代码,LOCK里再加一个System.Threading.Thread.Sleep(1000);
      

  18.   

    你再精确到纳秒,再不行就读CPU时钟
      

  19.   

            private static int _identity = 0;
            private static readonly object identityLock = new object();
            private static int identity
            {
                get
                {
                    Monitor.Enter(identityLock);
                    int value = ++_identity;
                    Monitor.Exit(identityLock);
                    return value;
                }
            }
                string strtime = currentTime.ToString("yyyy-MM-dd HH:mm:ss:fff") + identity.ToString();如果你在给strtime赋值的时候已经加锁,直接下面就行
                string strtime = currentTime.ToString("yyyy-MM-dd HH:mm:ss:fff") + (++_identity).ToString();
      

  20.   

    to:sbwwkmyd
    硬加上一个序列号不行啊,前面的毫秒还是有重复
      

  21.   

    private void thdrun1()
      {
      //DateTime currentTime = new DateTime(); 去掉  while (true)
      {
      DateTime currentTime  = DateTime.Now; //写入循环内
      string strtime = currentTime.ToString("yyyy-MM-dd HH:mm:ss:fff");
      string strnr = "thd1write: " +strtime;
      writetxt(strnr);
      }
      }
     试试吧
      

  22.   


    加这个是为了告诉你,没有同时写文件,时间肯定要放到写的时候啦,5毫秒是没有意义的,因为线程定时器精度只有70多毫秒。
    private void writetxt(string strnr)
    {
    string Sendpath = Application.StartupPath + "\\" + "Send_log.txt";
    lock (this)
    {
    FileStream FSSend = new FileStream(Sendpath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
    StreamWriter sw = new StreamWriter(FSSend);
    string strtime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fffffff");
    sw.WriteLine(strnr+strtime);
    System.Threading.Thread.Sleep(100);
    sw.Close();
    }
    } private void thdrun1()
    {
    while (bthd1)
    {
    string strnr = "thd1write: ";
    writetxt(strnr);
    }
    } private void thdrun2()
    {
    while (bthd2)
    {
    string strnr = "thd2write: ";
    writetxt(strnr);
    }
    } private void button1_Click(object sender, EventArgs e)
    {
    bthd1 = true;
    bthd2 = true;
    thd1 = new Thread(new ThreadStart(thdrun1));
    thd2 = new Thread(new ThreadStart(thdrun2));
    thd1.Start();
    thd2.Start(); } private void button2_Click(object sender, EventArgs e)
    {
    bthd1 = false;
    thd1.Join();
    bthd2 = false;
    thd2.Join();
    }
      

  23.   

    我本地15ms就不会重复了,这个DateTime的ms太不精确了
    Thread.Sleep(15);
      

  24.   

    因为DateTime.Now时间精度不够,大概在十几ms~几十ms之间
    跑几次Lock(this),取DateTime.Now时,取得的时间是相等的,并不是Lock没生效.8楼已经给出解了.如果真的需要这么精确,可以用API,去取系统时钟Windows的API函数 QueryPerformanceCounter和QueryPerformanceFrequecy
      

  25.   

    windows系统时间是每10-15ms更新一次,最好用windows API取CPU时间。
      

  26.   

    public class SynchThread
    {
      public void AddData(Object obj) //添加数据
      {
        MsgCacheList.Enqueue(obj); //加入队列
      }
      
      public void DealMsgQueue(Queue MsgCacheList) //处理命令队列
      {
        lock(MsgCacheList.SyncRoot)
        {
           Object item = MsgCacheList.Dequeue();
           AddLog(item); //这里是你要实现写日志的函数
        }
      }  public static Queue MsgCacheList; //静态队列
    }
    此外  DealMsgQueue 方法需要用一个委托的方法实现
      

  27.   

    楼上的,不要打消我的钻研的积极性,还有上面的多线程开启后,CPU占用特别高,是怎么回事儿 ?
      

  28.   

    大量线程排队不仅仅会造成CPU高,而且会可能不停的切换上下文(不做正事)造成假死,最后用单线程的队列做。
    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Reflection;namespace showjim.sys.threading
    {
        /// <summary>
        /// 队列处理线程
        /// </summary>
        /// <typeparam name="valueType">队列处理值类型</typeparam>
        public class queue<valueType>
        {
            #region 队列处理信息
            /// <summary>
            /// 队列处理信息
            /// </summary>
            private class queueInfo
            {
                /// <summary>
                /// 待处理对象
                /// </summary>
                public valueType value;
                /// <summary>
                /// 处理委托
                /// </summary>
                public showjim.sys.run<valueType> onProcess;
            }
            #endregion        /// <summary>
            /// 队列操作锁
            /// </summary>
            private object queueLock = new object();
            /// <summary>
            /// 待处理队列
            /// </summary>
            private List<queueInfo> queues = new List<queueInfo>();
            /// <summary>
            /// 队列处理线程
            /// </summary>
            private Thread queueThreadHandle;
            /// <summary>
            /// 处理委托
            /// </summary>
            private showjim.sys.run<valueType> onProcess;
            /// <summary>
            /// 暂停或恢复队列处理线程
            /// </summary>
            public bool _isPause = false;
            /// <summary>
            /// 暂停或恢复队列处理线程
            /// </summary>
            public bool isPause
            {
                set
                {
                    if (value) close(true);
                    else add(null);
                }
            }        #region 初始化队列处理线程
            /// <summary>
            /// 初始化队列处理线程
            /// </summary>
            /// <param name="onProcess">处理委托</param>
            public queue(showjim.sys.run<valueType> onProcess)
            {
                this.onProcess = onProcess;
            }
            #endregion        #region 关闭队列处理线程
            /// <summary>
            /// 关闭队列处理线程
            /// </summary>
            ~queue() { close(false); }
            /// <summary>
            /// 关闭队列处理线程
            /// </summary>
            /// <param name="isPause">是否暂停队列处理线程</param>
            public void close(bool isPause)
            {
                Thread handle = null;
                Monitor.Enter(queueLock);
                try
                {
                    _isPause = isPause;
                    if (queueThreadHandle != null)
                    {
                        handle = queueThreadHandle;
                        queueThreadHandle = null;
                        if (!isPause) queues.Clear();
                    }
                }
                finally { Monitor.Exit(queueLock); }
                if (handle != null && handle.IsAlive) handle.Abort();
            }
            #endregion        #region 添加待处理对象
            /// <summary>
            /// 添加待处理对象
            /// </summary>
            /// <param name="value">待处理对象</param>
            public void add(valueType value) { add(new queueInfo { value = value, onProcess = null }); }
            /// <summary>
            /// 添加待处理对象
            /// </summary>
            /// <param name="value">待处理对象</param>
            /// <param name="onProcess">处理委托</param>
            public void add(valueType value, showjim.sys.run<valueType> onProcess) { add(new queueInfo { value = value, onProcess = onProcess }); }
            /// <summary>
            /// 添加待处理对象
            /// </summary>
            /// <param name="value">待处理对象信息</param>
            private void add(queueInfo value)
            {
                Thread handle = null;
                Monitor.Enter(queueLock);
                try
                {
                    if (this.onProcess != null || value == null || value.onProcess != null)
                    {
                        if (value != null) queues.Add(value);
                        if (queueThreadHandle == null && (value == null || !_isPause) && queues.Count != 0) handle = queueThreadHandle = new Thread(new ThreadStart(queueThread));
                    }
                }
                finally { Monitor.Exit(queueLock); }
                if (handle != null)
                {
                    handle.IsBackground = true;
                    handle.Start();
                }
            }
            #endregion        #region 队列处理线程
            /// <summary>
            /// 队列处理线程
            /// </summary>
            public void queueThread()
            {
                for (queueInfo value = next(); value != null; value = next())
                {
                    try { (value.onProcess == null ? this.onProcess : value.onProcess)(value.value); }
                    catch (Exception error) { showjim.sys.exception.debug.writeDebug(MethodBase.GetCurrentMethod(), typeof(valueType).FullName + " 队列处理失败", error); }
                }
            }
            /// <summary>
            /// 获取下一个待处理对象
            /// </summary>
            /// <returns>待处理对象</returns>
            private queueInfo next()
            {
                queueInfo value = null;
                Thread handle = null;
                Monitor.Enter(queueLock);
                if (queueThreadHandle != null && queues.Count != 0)
                {
                    value = queues[0];
                    queues.RemoveAt(0);
                }
                else
                {
                    handle = queueThreadHandle;
                    queueThreadHandle = null;
                }
                Monitor.Exit(queueLock);
                if (handle != null)
                {
                    if (handle.IsAlive)
                    {
                        try { handle.Abort(); }
                        catch { }
                    }
                }
                return value;
            }
            #endregion
        }
    }
      

  29.   

    1.楼主使用毫秒级时间记录,肯定会出现重复,因为写日志的时间比毫秒级要短;
    2.CPU占用高,是因为楼主的程序中线程根本不Sleep,当然会很高,线程是什么?是死循环,CPU能占用不高吗?
    3.请在取时间的时候进行锁定操作,否则不可能不出现时间重复现象,如果你取时间的时候是重复的,你写日志再怎么锁也是重复的