none
如何使一段代码不被其它进程中断 RRS feed

  • 问题

  • 程序中有一段从服务器copy图像的代码,耗时比较长,如何实现Copy图像的过程一次完整执行完,使用Lock不行,请指教,谢谢!
    guiwenyang
    2010年4月6日 7:07

答案

  • 这看起来像是一个事务。

    你可以这样考虑。

    1 将文件拷到本地,并以为它取一个临时的文件名。

    2 全部 Copy 成功后将临时文件名改为正式的。

    下面的代码是伪代码,但基础描述了我上面的意思。

    1 所需要的类

    class CopyFile : IDisposable
    {
        public class CopyInfo
        {
            /// <summary>
            /// 源文件地址
            /// </summary>
            public string SourceFilePath { get; set; }
            /// <summary>
            /// 目标文件地址
            /// </summary>
            public string TargetFilePath { get; set; }
            /// <summary>
            /// 目标文件临时地址
            /// </summary>
            public string TempFilePath { get { return string.Format("{0}.tmp", Path.GetFileNameWithoutExtension(TargetFilePath)); } }
            public CopyInfo(string sourceFilePath, string targetFilePath)
            {
                this.SourceFilePath = sourceFilePath;
                this.TargetFilePath = targetFilePath;
            }
        }
    
        bool complete = false;
        CopyInfo[] fileInfo;
    
        public CopyFile(CopyInfo[] fileInfo)
        {
            this.fileInfo = fileInfo;
        }
    
        public void Copy()
        {
            // 将源文件拷到本地计算机上,同时以临时文件名保存。
            foreach (CopyInfo c in this.fileInfo)
            {
                File.Copy(c.SourceFilePath, c.TempFilePath);
            }
        }
    
        public void Complete()
        {
            this.complete = true;
        }
    
        public void Dispose()
        {
            if (this.complete)
            {
                // 若全部成功,将临时的的文件名,改为正式的文件名。
                foreach (CopyInfo c in this.fileInfo)
                {
                    File.Move(c.TempFilePath, c.TargetFilePath);
                }
            }
            else
            {
                // 若失败,删除临时的文件名。
                foreach (CopyInfo c in this.fileInfo)
                {
                    if (File.Exists(c.TempFilePath))
                        File.Delete(c.TempFilePath);
                }
            }
        }
    }

    2 使用方法:

    void DoCopy()
    {
        CopyFile.CopyInfo[] info = new CopyFile.CopyInfo[]{
            new CopyFile.CopyInfo(@"\\192.168.1.1\1.jpg", @"C:\Files\1.jpg"),
            new CopyFile.CopyInfo(@"\\192.168.1.1\2.jpg", @"C:\Files\2.jpg"),
            new CopyFile.CopyInfo(@"\\192.168.1.1\3.jpg", @"C:\Files\3.jpg")
        };
    
        using (CopyFile cf = new CopyFile(info))
        {
            cf.Copy();
            cf.Complete(); // copy 成功
        }
    }


    知识改变命运,奋斗成就人生!
    2010年4月6日 8:36
    版主
  • 程序中有一段从服务器copy图像的代码,耗时比较长,如何实现Copy图像的过程一次完整执行完,使用Lock不行,请指教,谢谢!
    guiwenyang


    就问题本身来看,楼主引入了一个原子化 (Atomize) 的问题,也就是,如何将一种连续操作变成原子操作,要么全部执行,要么都不执行。

    目前的 .NET Framework 尚未具备完全的原子操作支持,但已经进入了一些类型,如 Interlocked 和 TransactionScope,可以在不同程度上实现一些原子操作 (事务具备原子性)。如果楼主有兴趣,可以去 MSDN DevLabs 找一个叫 STM.NET 的项目,相信对您有帮助。比如,利用 STM,您可以这样:

    public int Foo()
    {
        int a = 0, b = 0;
        atomic
        {
            a++;
            a += b++;
        }
        return a + b;
    }

     


    Mark Zhou
    2010年4月6日 10:00

全部回复

  • 你好!

    耗时较长的任务最好采用分段执行,减少软硬件异常后的损失。

    比如你要 COPY 1W 个图像,在 Copy 到第 5000 张时停电了。那么下次 Copy 应该从第 5001 个图像开始。


    知识改变命运,奋斗成就人生!
    2010年4月6日 7:11
    版主
  • 我只Copy3幅图像,这三幅图像是一个整体的要么都有要么都没有
    guiwenyang
    2010年4月6日 7:16
  • 这看起来像是一个事务。

    你可以这样考虑。

    1 将文件拷到本地,并以为它取一个临时的文件名。

    2 全部 Copy 成功后将临时文件名改为正式的。

    下面的代码是伪代码,但基础描述了我上面的意思。

    1 所需要的类

    class CopyFile : IDisposable
    {
        public class CopyInfo
        {
            /// <summary>
            /// 源文件地址
            /// </summary>
            public string SourceFilePath { get; set; }
            /// <summary>
            /// 目标文件地址
            /// </summary>
            public string TargetFilePath { get; set; }
            /// <summary>
            /// 目标文件临时地址
            /// </summary>
            public string TempFilePath { get { return string.Format("{0}.tmp", Path.GetFileNameWithoutExtension(TargetFilePath)); } }
            public CopyInfo(string sourceFilePath, string targetFilePath)
            {
                this.SourceFilePath = sourceFilePath;
                this.TargetFilePath = targetFilePath;
            }
        }
    
        bool complete = false;
        CopyInfo[] fileInfo;
    
        public CopyFile(CopyInfo[] fileInfo)
        {
            this.fileInfo = fileInfo;
        }
    
        public void Copy()
        {
            // 将源文件拷到本地计算机上,同时以临时文件名保存。
            foreach (CopyInfo c in this.fileInfo)
            {
                File.Copy(c.SourceFilePath, c.TempFilePath);
            }
        }
    
        public void Complete()
        {
            this.complete = true;
        }
    
        public void Dispose()
        {
            if (this.complete)
            {
                // 若全部成功,将临时的的文件名,改为正式的文件名。
                foreach (CopyInfo c in this.fileInfo)
                {
                    File.Move(c.TempFilePath, c.TargetFilePath);
                }
            }
            else
            {
                // 若失败,删除临时的文件名。
                foreach (CopyInfo c in this.fileInfo)
                {
                    if (File.Exists(c.TempFilePath))
                        File.Delete(c.TempFilePath);
                }
            }
        }
    }

    2 使用方法:

    void DoCopy()
    {
        CopyFile.CopyInfo[] info = new CopyFile.CopyInfo[]{
            new CopyFile.CopyInfo(@"\\192.168.1.1\1.jpg", @"C:\Files\1.jpg"),
            new CopyFile.CopyInfo(@"\\192.168.1.1\2.jpg", @"C:\Files\2.jpg"),
            new CopyFile.CopyInfo(@"\\192.168.1.1\3.jpg", @"C:\Files\3.jpg")
        };
    
        using (CopyFile cf = new CopyFile(info))
        {
            cf.Copy();
            cf.Complete(); // copy 成功
        }
    }


    知识改变命运,奋斗成就人生!
    2010年4月6日 8:36
    版主
  • 程序中有一段从服务器copy图像的代码,耗时比较长,如何实现Copy图像的过程一次完整执行完,使用Lock不行,请指教,谢谢!
    guiwenyang


    就问题本身来看,楼主引入了一个原子化 (Atomize) 的问题,也就是,如何将一种连续操作变成原子操作,要么全部执行,要么都不执行。

    目前的 .NET Framework 尚未具备完全的原子操作支持,但已经进入了一些类型,如 Interlocked 和 TransactionScope,可以在不同程度上实现一些原子操作 (事务具备原子性)。如果楼主有兴趣,可以去 MSDN DevLabs 找一个叫 STM.NET 的项目,相信对您有帮助。比如,利用 STM,您可以这样:

    public int Foo()
    {
        int a = 0, b = 0;
        atomic
        {
            a++;
            a += b++;
        }
        return a + b;
    }

     


    Mark Zhou
    2010年4月6日 10:00