c# - 当我尝试使用线程重命名我的文件名并关闭并刷新 FileStream 时,它会给我错误 Cannot access a closed file
问题描述
我有大量数据,我需要每 5 秒制作一次“.txt”文件,并将下一个数据写入新创建的“.txt”文件中,但是当我尝试使用 Timer 线程时,有时程序运行正常但是一段时间后,它将通过异常无法访问已关闭的文件。请在我的代码中帮助我并建议我必须做什么。
public class Program
{
public static void Main(string[] args)
{
Service s = new Service();
s.init();
}
}
class Service
{
FileStream fs = null;
int filecount = 0;
long a = 1000000000000000;
// int j = 0;
public void init()
{
initialiseFile(filecount);
timer();
WriteINFile();
}
private void initialiseFile( int filecount)
{
fs = File.Create("C:\\Users\\yogesh.ghonate\\source\\repos\\ConsoleApp3\\ConsoleApp3\\NewFolder1\\Index_" + filecount + ".txt");
}
private void WriteINFile()
{
string sen = " write in file ";
for (int i = 0; i < a; i++)
{
Byte[] title = new UTF8Encoding(true).GetBytes(sen);
fs.Write(title, 0, title.Length);
}
}
public void timer()
{
System.Timers.Timer th = new System.Timers.Timer();
th.Interval = 5000;
th.Elapsed += new ElapsedEventHandler(run);
th.Start();
run(th, null);
}
public void run(object state, ElapsedEventArgs e)
{
Commitzfile();
}
private void Commitzfile()
{
//Stopwatch stopwatch = new Stopwatch();
//stopwatch.Start();
fs.Flush();
fs.Close();
// fs.Dispose();
//stopwatch.Stop();
filecount++;
initialiseFile(filecount);
}
}
解决方案
最严格的解决方案是添加lock
到您的代码中。这将防止任何竞争条件,也会使您的代码变慢一点,因为它会在资源正在使用时阻塞线程。
你可以像这样使用它:
// add new lock object
object lockObject = new object();
FileStream fs = null;
int filecount = 0;
long a = 1000000000000000;
…
private void WriteINFile()
{
string sen = " write in file ";
for (int i = 0; i < a; i++)
{
Byte[] title = new UTF8Encoding(true).GetBytes(sen);
lock (lockObject)
{
fs.Write(title, 0, title.Length);
}
}
}
…
private void Commitzfile()
{
lock(lockObject)
{
fs.Flush();
fs.Close();
filecount++;
initialiseFile(filecount);
}
}
我建议您阅读以下有关lock 语句的文档
更新
在并发编程中,有许多问题需要考虑。其中之一是资源管理。通常这个问题是与哲学家就餐问题一起出现的。当一个资源被多个进程/线程尝试使用时,主要问题就会发生,但该资源必须一次被一个使用。在您的情况下,它是 FileStream,因为一个线程一直在尝试写入它,而在另一个线程上它是关闭并更改的。您可以看到,在某些情况下,可能会发生一个关闭流而另一个仍试图同时写入它的情况。要克服这个问题,您需要确保一次只能由一个线程访问资源。执行此操作的一种工具是 lock 语句。
其他要记住的事情:
- 死锁。
- 有多少并发线程值得同时运行。
希望这个简短的总结有所帮助。如果您需要更多信息,请随时提出新问题(或查找是否已有问题)。
推荐阅读
- mongodb - Graphql创建两个查询之间的关系。初始化前错误无法访问
- r - 我想在 r 语言中查找和删除包含某些数据的行?
- kotlin - Kotlin - 从两个线程访问集合时如何锁定集合
- c# - 使用 DbConnection 初始化 EF Core DbContext 连接
- wordpress - 根据表单输入更改弹出消息
- javascript - React Hooks TypeScript 事件和状态类型
- rocket.chat - 如何/在哪里使用房间模板
- python - 如何交换中间字母和最后一个字母交换?
- c# - 单击列标题时的WPF GridView排序
- android - View.draw(canvas) 子视图质量差