Параллельный доступ к файлу - PullRequest
0 голосов
/ 23 февраля 2020

Я запускаю несколько экземпляров приложения, которое читает первую строку из файла, затем удаляет первую строку и сохраняет файл под тем же именем. Я обнаружил, что в некоторых случаях приложения будут взламывать sh. Я создал образец программы, чтобы лучше понять возникающие у меня проблемы. Если я запускаю четыре экземпляра этой программы, иногда несколько экземпляров пытаются удалить одну и ту же строку. В конце концов, операция проходит успешно, но она неэффективна. Как я могу улучшить код, чтобы избежать этого? Возможно, каждый экземпляр должен заблокировать файл, пока он его использует.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Diagnostics;

namespace ConcurrentFileAccess
{
    public partial class MainForm : Form
    {
        bool gbAbort = false;
        public MainForm()
        {
            InitializeComponent();
        }

        void BtnCreateFileClick(object sender, EventArgs e)
        {
            string sFile = @"S:\Temp\concurrentFileAccess.txt";
            Stopwatch stopwatch = Stopwatch.StartNew();
            if (File.Exists(sFile)) {
                File.Delete(sFile);
            }

            if (!File.Exists(sFile)) {
                List<string> list = new List<string>();
                var fc = File.Create(sFile);
                fc.Close();
                for (int i = 1; i <= 200; i++) {
                    list.Add(i.ToString());
                }

                File.WriteAllLines(sFile, list);
                listBox1.Items.Add("File " + sFile + " was created and it contains 200 lines");
            } else {
                string[] lines = File.ReadAllLines(sFile);
                int nlines = lines.Length;
                listBox1.Items.Add("File " + sFile + " already exists and it contains " + nlines + " lines");
            }

            stopwatch.Stop();
            listBox1.Items.Add("File created in " + stopwatch.Elapsed.ToString("hh\\:mm\\:ss\\.fff"));          
        }

        void BtnDeleteFromFileClick(object sender, EventArgs e)
        {
            gbAbort = false;
            int nlines = 9999;
            while (nlines > 0) {
                nlines = DeleteOneLine();
                Application.DoEvents();
                if (gbAbort) {
                    return;
                }
            }
        }

        int DeleteOneLine()
        {
            string sFile = @"S:\Temp\concurrentFileAccess.txt";
            listBox1.Items.Add("We are in DeleteLines()...");
            listBox1.SelectedIndex = listBox1.Items.Count - 1;
            Application.DoEvents();

            int nLinesLeft = 9999;
            string line0 = string.Empty;
            Stopwatch stopwatch = Stopwatch.StartNew();
            int ntry = 0;
            while (ntry < 100) {
                try {
                    string[] lines = File.ReadAllLines(sFile);
                    List<string> list = new List<string>(lines);
                    nLinesLeft = list.Count;
                    if (nLinesLeft > 0) {
                        line0 = list[0];
                        list.RemoveAt(0);
                        listBox1.Items.Add("Deleted line " + line0);
                        listBox1.SelectedIndex = listBox1.Items.Count - 1;
                        Application.DoEvents();
                        listBox1.Items.Add("Writing to file after line " + line0 + " was deleted");
                        File.WriteAllLines(sFile, list);
                        nLinesLeft = list.Count;
                        Application.DoEvents();
                    } else {
                        nLinesLeft = 0;
                        break;
                    }
                } catch (Exception) {
                    ntry++;
                    listBox1.Items.Add("ntry = " + ntry + ", could not delete line " + line0 + " from file. Attempting again...");
                    listBox1.SelectedIndex = listBox1.Items.Count - 1;
                    Application.DoEvents();
                    Application.DoEvents();
                    Thread.Sleep(50);
                }
            }

            if(ntry >= 100) {
                nLinesLeft = -1; // should never get here
            }

            stopwatch.Stop();
            listBox1.Items.Add("ntry: " + ntry + ", lines Left: " + nLinesLeft + ", elapsed = " + stopwatch.Elapsed.ToString("hh\\:mm\\:ss\\.fff"));
            listBox1.SelectedIndex = listBox1.Items.Count - 1;
            Application.DoEvents();
            return nLinesLeft;
        }

        void BtnAbortClick(object sender, EventArgs e)
        {
            gbAbort = true;
        }

        void BtnOpenAppFolderClick(object sender, EventArgs e)
        {
            string sFile = Application.ExecutablePath;
            string sPath = Path.GetDirectoryName(sFile);
            Process.Start(sPath);
        }

        void BtnOpenFileClick(object sender, EventArgs e)
        {
            string sFile = @"S:\Temp\concurrentFileAccess.txt"; 
            if(File.Exists(sFile)) {
                Process.Start(sFile);
            }
            else {
                MessageBox.Show("File " + sFile + " not found");
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...