请C#高手指点下java多线程问题题错哪儿了?

下次自动登录
现在的位置:
& 综合 & 正文
C# 多线程目录拷贝 文件拷贝
最近在旧项目升级中遇到一个问题。把它记录下来,以便日后查看。本人新手,其中不足还需高手指点,解答小z的疑问。
疑问:在Window7中测试直接拷贝文件在250项/秒左右。但是在通过程序中控制线程数量,并且通过分配线程的任务来拷贝,始终速度都没有达到理想值。
问题:旧项目在存放图片附件是分别存放在DownFile 、UpFile 两个文件夹内(分为两类文件),系统运行时间一久,里面文件也越来越多,管理起来非常麻烦。每次在打开这两个文件夹总是无响应。
新项目需求:这两类文件分别是月为单位存放在文件夹内,文件名保持不变,文件根路径格式/DownFile/yyMM。通过写一个小程序来拷出图片附件。
旧目录DownFile中存放的文件命名规则是:(DateTime.Now.Ticks)+扩展名 。
目录UpFile中文件命名规则是:(大写"R" + yyMMddhhmmssfff) + 扩展名。
根据文件名字中提取年月来决定存放路径。现将拷贝文件的方式在代码中展示。
程序配置文件:app.config
&?xml version="1.0" encoding="utf-8"?&
&configuration&
&appSettings&
&!--线程数量--&
&add key="ThreadCount" value="8" /&
&!--文件源路径 DownFUpFile--&
&add key="SourceDir" value="C:\Users\Administrator\Desktop\DownFC:\Users\Administrator\Desktop\UpFile" /&
&!--目标存放路径--&
&add key="ToDir" value="C:\Users\Administrator\Documents\Visual Studio 2008\Projects\ThreadCopyFile\CopyFileToDirectory\bin\Debug\CopyFolder" /&
&/appSettings&
&/configuration&
代码文件:ThreadCopyFile2.cs
/// &summary&
/// 多线程-参数类
/// &/summary&
public class SplitArr
public int thread_id { }
public int start_index { }
public int end_index { }
/// &summary&
/// 多线程文件拷贝
/// &/summary&
public class ThreadCopyFile2
#region 属性
private List&Thread& threadList = new List&Thread&();//线程列表
private event EventHandler OnNumberC//任务执行完成引发的事件
private Stopwatch sw = new Stopwatch();//时间计数
private int counter = 1;//处理任务的个数
private List&string& stringL//文件列表
private int total = 0;//文件总个数
#endregion
/// &summary&
/// 程序入口
/// &/summary&
public static void Main()
ThreadCopyFile2 tcf = new ThreadCopyFile2();
tcf.StartWrok();
#region 线程工作内容
/// &summary&
/// 初始化-并启动工作线程
/// &/summary&
public ThreadCopyFile2()
//加载文件列表
InitFileList();
//初始进度条
ProcessBarInit();
int ThreadCount = Convert.ToInt32(ConfigurationManager.AppSettings["ThreadCount"]);
//设置线程工作范围
Dictionary&int, int[]& root = Splice(stringList, ThreadCount);
//设置线程
for (int i = 0; i & ThreadC i++)
Thread thread = new Thread(new ParameterizedThreadStart(CopyFile));
thread.Name = i.ToString();//设置线程ID
//线程工作范围
SplitArr sa = new SplitArr();
sa.thread_id =
sa.start_index = root[i][0];
sa.end_index = root[i][1];
thread.Start(sa);//启动线程
threadList.Add(thread);
//线程完成执行事件
OnNumberClear += new EventHandler(CompleteEvent);
/// &summary&
/// 加载文件列表
/// &/summary&
private void InitFileList()
var SourceDir = ConfigurationManager.AppSettings["SourceDir"];
string[] path = SourceDir.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
//获取文件列表
stringList = new List&string&();
stringList.AddRange(Directory.GetFiles(path[0]).Where&string&(f =& CheckExtion(f)));
stringList.AddRange(Directory.GetFiles(path[1]).Where&string&(f =& CheckExtion(f)));
total = stringList.C//文件总个数
/// &summary&
/// 开始工作
/// &/summary&
public void StartWrok()
//计时器-开始工作
sw.Start();
/// &summary&
/// 线程锁
/// &/summary&
readonly object obj = new object();
/// &summary&
/// 文件拷贝
/// &/summary&
private void CopyFile(object _SplitArr)
SplitArr sa = _SplitArr as SplitA
if (sa != null)
var ToDir = ConfigurationManager.AppSettings["ToDir"];
string newPath = String.E//新路径
string newFilePath = String.E//文件新全路径
//Console.WriteLine("ID:" + sa.thread_id + "\tsa.start_index:" + sa.start_index + "\tsa.end_index:" + sa.end_index);
int tempNum = sa.start_
while (tempNum &= sa.end_index)
string oldFilePath = stringList[tempNum];
fi = new FileInfo(oldFilePath);
//根据Source文件上一级路径做条件,返回相应新的存放路径
newPath = Path.Combine(ToDir, Path.Combine(fi.Directory.Name, AnalysisName(fi.Name, fi.Directory.Name)));
newFilePath = Path.Combine(newPath, fi.Name);
//判断新路径是否存在
if (!Directory.Exists(newPath)) { Directory.CreateDirectory(newPath); }
//判断目标路径是否存在该文件
if (!File.Exists(newFilePath) && File.Exists(fi.FullName))
File.Copy(fi.FullName, newFilePath);
////删除ArrayList中的元素
//stringList.RemoveAt(0);
//stringList.TrimExcess();
//累加任务数
counter++;
//判断是否处理完任务
if (stringList.Count == counter)
OnNumberClear(this, new EventArgs());//引发完成事件
//计算百分比
rate = CalcRate(counter);
//标题设置
Console.Title = "正在拷贝第【" + counter.ToString() + "】个文件;进度" + rate.ToString() + "%";
//设置进度条
SetProcessBar(rate - 1);
Thread.Sleep(1);
tempNum++;
/// &summary&
/// 执行完成执行的事件
/// &/summary&
/// &param name="sender"&&/param&
/// &param name="e"&&/param&
void CompleteEvent(object sender, EventArgs e)
sw.Stop();
Console.SetCursorPosition(0, 7);
Console.Write("执行完成,停止了所有线程的执行。成功拷贝文件:" + total.ToString() + "个,用时:" + sw.ElapsedMilliseconds.ToString() + "毫秒");
Console.Title = "成功拷贝文件【" + total.ToString() + "】个";
foreach (Thread thread in threadList)
thread.Abort();
#endregion
#region 公共函数
/// &summary&
/// 文件类型检查
/// &/summary&
/// &param name="ext"&&/param&
/// &returns&&/returns&
bool CheckExtion(string ext)
return ext.EndsWith(".bmp") || ext.EndsWith(".jpg") || ext.EndsWith(".jpeg") || ext.EndsWith(".png") || ext.EndsWith(".gif") || ext.EndsWith(".tif");
/// &summary&
/// 根据文件名分析存放路径
/// &/summary&
/// &param name="fileName"&&/param&
/// &param name="flag"&&/param&
/// &returns&&/returns&
string AnalysisName(string fileName, string flag)
switch (flag)//根据标识判断要返回的路径
case "DownFile":
string name1 = Regex.Match(fileName, "\\d*(?=\\.)").V
var time = new DateTime(Convert.ToInt64(name1));
return time.ToString("yyMM");
case "UpFile":
return Regex.Match(fileName, "(?&=R)\\d{4}").Groups[0].V
return "";
/// &summary&
/// 分割集合
/// &/summary&
/// &param name="oldStr"&要分割的字符串&/param&
/// &param name="length"&分割后次数&/param&
/// &returns&&/returns&
private static Dictionary&int, int[]& Splice(List&string& oldArray, int length)
Dictionary&int, int[]& root = new Dictionary&int, int[]&();
int count = oldArray.C
if (count & length)
int num = count /
int last = count %//剩余的元素个数
bool temp =
if (last & 0)
int tempNum = 0;
for (int i = 1; i &= i++)
if ((i - 1) == 0)
int rst = (temp ? num - 1 : num) - 1;
root.Add(i - 1, new int[] { 0, rst });
tempNum = rst + 1;
else if (i == length)
root.Add(i - 1, new int[] { tempNum, count - 1 });
int rst = root[0][1] * i + 1;
root.Add(i - 1, new int[] { tempNum, rst });
root.Add(0, new int[] { length });
#endregion
#region 进度条
/// &summary&
/// 初始化进度条
/// &/summary&
void ProcessBarInit()
Console.WriteLine("\n************************工作进度************************\n");
Console.Write(" ");
Console.BackgroundColor = ConsoleColor.G
for (int i = 1; i &= 50; i++)
Console.Write(" ");
Console.BackgroundColor = ConsoleColor.B
Console.Write("");
Console.SetCursorPosition(0, 4);
Console.Write("\n********************************************************\n");
/// &summary&
/// 设置进度
/// &/summary&
/// &param name="position"&&/param&
void SetProcessBar(int position)
Monitor.Enter(obj);
//绘制进度条进度
Console.BackgroundColor = ConsoleColor.G//设置进度条颜色
Console.SetCursorPosition(position / 2 + 1, 3);//设置光标位置,参数为第几列和第几行
Console.Write(" ");//移动进度条
Console.BackgroundColor = ConsoleColor.B//恢复输出颜色
Console.SetCursorPosition(52, 3);//设置光标位置,参数为第几列和第几行
Console.Write((position + 1).ToString() + "%");//移动进度条
Monitor.Exit(obj);
/// &summary&
/// 计算百分比
/// &/summary&
/// &param name="count"&&/param&
/// &returns&&/returns&
int CalcRate(int count)
int result = Convert.ToInt32((float)count / (float)total * 100);
#endregion
【上篇】【下篇】c#多线程访问数据库
作者: 发布于:日 13:34
推荐课程:基于C# Winform下C/S架构的大管家固定资产管理系统(结合高级控件应用)
推荐课程:C#培训推荐:基础+项目实战打造C/S高手(C#系列培训)
更多教程访问:
来源: 原文链接:
( 内容完 )
您可能还对这些文章感兴趣:
赞助商链接
www.0771bc.com
tw.ibeifeng.com
http://www.ibeifeng.com/source_list.php请熟悉C#线程访问主线程控件的高手指点一下,感谢
[问题点数:20分,结帖人pegasus827]
请熟悉C#线程访问主线程控件的高手指点一下,感谢
[问题点数:20分,结帖人pegasus827]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
2002年10月 VC/MFC大版内专家分月排行榜第一2004年1月 软件工程/管理大版内专家分月排行榜第一2003年1月 软件工程/管理大版内专家分月排行榜第一
匿名用户不能发表回复!|工作中遇到的一个多线程下导致RCW无法释放的问题_C#应用_动态网站制作指南
工作中遇到的一个多线程下导致RCW无法释放的问题
来源:人气:586
最近有个同事在调用一个类库中的方法时遇到了一个问题,异常信息如下:
尝试释放正在使用的RCW,活动线程或其他线程上正在使用该 RCW,释放正在使用的 RCW 的尝试会导致损坏或数据丢失。
该方法中对文件进行相关了操作,因为我之前也在多线程环境下调用过该方法,并且没遇到这个问题,所以同事让我过去看看怎么回事。这个方法在对文件进行相关操作后,会调用另外一个方法释放word对象,部分代码如下:
Word._ t = oWord as Word._A
object oIsSave =
t.Quit(ref oIsSave, ref oMissing, ref oMissing);
System.Runtime.InteropServices.Marshal.ReleaseComObject(oDoc);
System.Runtime.InteropServices.Marshal.ReleaseComObject(oWord);
GC.Collect();
GC.Collect();
该段代码是为了保证立即释放word对象并关闭word进程。因为异常信息定位在这里,所以我过去后就从这里开始看,但是看了半天,也没看出类库中的方法有什么问题,因为之前我使用的时候没遇到这种情况,因此我觉得可能不会是这里的问题,并且我负责的那个产品已经经过了大量的测试,肯定是没问题的,所以我说让我看看你是怎么调用的吧,打开他的代码看了一眼,整体上没什么其他问题,但是有个地方引起了我的注意,代码中对该类的实例化放在了全局范围,因为是个cs项目,这么做会导致该对象始终被引用,因此即使在垃圾回收时也无法被释放,而这里调用的又是com,就导致了word进程无法关闭,并且同事在这里用的是多线程,所以程序一运行起来,会出现一大堆word进程关不掉。于是就将这里的对象实例化放到了线程方法中,这样在方法执行结束后,堆中的对象就处于无引用状态,在垃圾回收时就被释放了,问题就自然解决了。其实这里跟单线程还是多线程没关系,主要是在全局范围内进行实例化导致了对象不能被垃圾回收,所以在写代码的时候一定要注意对象的生命周期。
优质网站模板}

我要回帖

更多关于 多线程安全问题 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信