c#双线程,线程.IsAlive是false,即使这个线程还没有完成
本文关键字:线程 还没有 false IsAlive | 更新日期: 2023-09-27 18:07:33
我写了一个简短的程序,它搜索空目录并删除它们。这个进程应该在后台运行,而另一个进程应该每秒向控制台写入一些内容,以便用户知道程序仍在运行。我的问题是整个程序在大约3秒后停止,而processDirectory方法甚至没有完成。
My Main Method调用在第二个线程中运行的方法(processDirectory()):
static void Main(string[] args)
{
Thread delEmpty = new Thread(() => Thread2.processDirectory(@"C:'Users'Mani'Documents"));
delEmpty.Start();
printRunning(delEmpty);
File.WriteAllLines(@"C:'Users'Mani'Desktop'Unauthorized Folders.txt", Thread2.unauthorized);
File.WriteAllLines(@"C:'Users'Mani'Desktop'Empty Folders.txt", Thread2.emptyFolders);
Console.ReadKey();
}
我的第二个类,存储我的processDirectory方法,应该在后台运行:
public static List<string> unauthorized = new List<string>();
public static List<string> emptyFolders = new List<string>();
public static void processDirectory(string rootPath)
{
if (!Directory.Exists(rootPath)) return;
foreach (var dir in Directory.GetDirectories(rootPath))
{
try
{
processDirectory(dir);
if (Directory.GetFiles(dir).Length == 0 && Directory.GetDirectories(dir).Length == 0) Directory.Delete(dir, false);
}
catch (UnauthorizedAccessException uae) { unauthorized.Add(uae.Message); }
}
}
打印代码:
static async void printRunning(Thread delEmpty)
{
Console.CursorVisible = false;
for (int cnt = 1; delEmpty.IsAlive; cnt++)
{
switch (cnt)
{
case 1:
Console.Write("Running. ");
break;
case 2:
Console.Write("Running . ");
break;
case 3:
Console.Write("Running .");
cnt = 0;
break;
}
await Task.Delay(1000);
}
Console.Write("Finished!");
Console.CursorVisible = true;
}
我建议您避免使用线程,而使用一个抽象来为您处理线程问题。我建议使用微软的响应式框架团队的响应式扩展(NuGet "System.Reactive")和交互式扩展(NuGet "System.Interactive")。
然后你可以这样做:
static void Main(string[] args)
{
var rootPath = @"C:'Users'Mani'Documents";
using (Observable
.Interval(TimeSpan.FromSeconds(1.0))
.Subscribe(x => Console.WriteLine($"Running{"".PadLeft((int)x % 3)}.")))
{
Thread2.processDirectory(rootPath);
}
}
public static class Thread2
{
public static List<string> unauthorized = new List<string>();
public static List<string> emptyFolders = null;
public static void processDirectory(string rootPath)
{
if (!Directory.Exists(rootPath)) return;
emptyFolders =
EnumerableEx
.Expand(Directory.GetDirectories(rootPath), dir => Directory.GetDirectories(dir))
.Where(dir => Directory.GetFiles(dir).Length == 0 && Directory.GetDirectories(dir).Length == 0)
.ToList();
emptyFolders
.AsEnumerable()
.Reverse()
.ForEach(dir =>
{
try
{
Directory.Delete(dir, false);
}
catch (UnauthorizedAccessException uae) { unauthorized.Add(uae.Message); }
});
}
}
这里的关键元素是:
-
Observable.Interval
设置定时器,每秒显示"Running"消息。 -
EnumerableEx.Expand
,它递归地构建要删除的文件夹列表。 - 运行要删除的文件夹(反向)并删除它们的
Reverse/ForEach
。
处理GetDirectories
抛出错误的情况,使用以下代码:
Func<string, string[]> getDirectories = dir =>
{
try
{
return Directory.GetDirectories(dir);
}
catch (UnauthorizedAccessException uae)
{
unauthorized.Add(uae.Message);
return new string[] { };
}
};
emptyFolders =
EnumerableEx
.Expand(getDirectories(rootPath), dir => getDirectories(dir))
.Where(dir => Directory.GetFiles(dir).Length == 0 && getDirectories(dir).Length == 0)
.ToList();
有两种解决方法:
- 让printRunning方法同步运行
-
添加
delEmpty.Join()
以便主线程在delEmpty线程完成时等待delEmpty.Start(); printRunning(delEmpty); delEmpty.Join();
在第一个解决方案的情况下,将printRunning
方法替换为以下方法
static void printRunning(Thread delEmpty)
{
Console.CursorVisible = false;
for (int cnt = 0; delEmpty.IsAlive; cnt++)
{
switch (cnt % 3)
{
case 0:
Console.Write("Running.");
break;
case 1:
Console.Write("Running..");
break;
case 2:
Console.Write("Running...");
break;
}
Thread.Sleep(1000);
Console.SetCursorPosition(0, 0);
Console.Clear();
}
Console.Write("Finished!");
Console.CursorVisible = true;
}