ไม่สามารถเขียนไปยังไฟล์ XML โดยใช้เธรดและ XDocument

string filepath = Environment.CurrentDirectory + @"Expense.xml";

public void  WriteToXML(object param)
{
Expense exp = (Expense)param;
   if (File.Exists(filepath)) {
    XDocument xDocument = XDocument.Load(filepath);

    XElement root = xDocument.Element("Expenses");
    IEnumerable<XElement> rows = root.Descendants("Expense");
    XElement firstRow = rows.First();

    firstRow.AddBeforeSelf(new XElement("Expense",
           new XElement("Id", exp.Id.ToString()),
           new XElement("Amount", exp.Amount.ToString()),
           new XElement("Contact", exp.Contact),
           new XElement("Description", exp.Description),
           new XElement("Datetime", exp.Datetime)));
    xDocument.Save(filepath);
 }
}

Expense exp = new Expense();
exp.Id = new Random().Next(1, 10000);
exp.Amount = float.Parse(text1[count].Text);
exp.Contact = combo1[count].SelectedItem.ToString();
exp.Description = rtext1[count].Text.ToString();
exp.Datetime = DateTime.Now.ToString("MM-dd-yyyy");

workerThread = new Thread(newParameterizedThreadStart(WriteToXML));
workerThread.Start(exp); // throws System.IO.IOException

ฉันไม่สามารถเขียนไปยังไฟล์ XML ด้วยดอกยางของผู้ปฏิบัติงาน - ฉันได้รับข้อผิดพลาดนี้:

System.IO.IOException: 'กระบวนการไม่สามารถเข้าถึงแฟ้ม 'C:\work\FinanceManagement\FinanceManagement\bin\DebugExpense.xml' ได้เนื่องจากกำลังถูกใช้โดยกระบวนการอื่น

แต่ถ้าฉันใช้มันแบบ WriteToXML(exp); มันก็ใช้งานได้ ฉันคิดว่า XDocument.Load(filepath) ไม่ปลอดภัยสำหรับเธรด ฉันจะแก้ไขปัญหานี้ได้อย่างไร?


person TRomesh    schedule 10.05.2019    source แหล่งที่มา
comment
บรรทัดแรกไม่ควรเป็น: string filepath = Path.Combine(Environment.CurrentDirectory, Expense.xml) ? ดูเหมือนว่าคุณหมายถึงเส้นทางที่จะเป็น bin\Debug\Expense.xml   -  person Metheny    schedule 10.05.2019
comment
มีมากกว่าหนึ่งเธรดในแต่ละครั้งหรือไม่?   -  person Crowcoder    schedule 10.05.2019
comment
@Crowcoder ฉันใช้ File.Exists(filepath) เพื่อตรวจสอบว่ามีไฟล์อยู่หรือไม่ ฉันได้อัปเดตโค้ดแล้ว   -  person TRomesh    schedule 10.05.2019
comment
File.Exists มีความเสี่ยงต่อสภาพการแข่งขัน หากคุณมีเธรดที่ทำงานใกล้กันมาก คุณสามารถรับหลายเธรดในบล็อกโค้ดนั้นพร้อมกันได้   -  person Crowcoder    schedule 10.05.2019
comment
@Metheny แย่ของฉัน ขอบคุณสำหรับการชี้ให้เห็น   -  person TRomesh    schedule 10.05.2019
comment
@Crowcoder ฉันยังใหม่กับ C# นิดหน่อย คุณช่วยแนะนำฉันแก้ไขปัญหานี้ได้ไหม   -  person TRomesh    schedule 10.05.2019
comment
@TRomesh หากนั่นเป็นสาเหตุของปัญหาของคุณ วิธีที่ง่ายที่สุดในการหลีกเลี่ยงอาจเป็น ใช้ lock หรืออย่าเพิ่งผลักดันงานนี้ไปที่เธรดใหม่ เหตุผลในการทำเช่นนั้นคืออะไร?   -  person Crowcoder    schedule 10.05.2019
comment
@Crowcoder ฉันต้องอ่าน/เขียน/อัปเดต xml โดยใช้ threads นั่นคือเหตุผลที่ฉันใช้วิธีนี้   -  person TRomesh    schedule 10.05.2019


คำตอบ (1)


ลองแนะนำ lock ดูว่าจะช่วยแก้ปัญหาได้หรือไม่:

// Declare this somewhere in your project, can be in same class as WriteToXML
static object XmlLocker;

จากนั้นล้อม lock รอบตรรกะ:

public void WriteToXML(object param)
{
    Expense exp = (Expense)param;

    lock (XmlLocker) // <-- this limits one thread at a time
    {
        if (File.Exists(filepath))
        {
            XDocument xDocument = XDocument.Load(filepath);

            XElement root = xDocument.Element("Expenses");
            IEnumerable<XElement> rows = root.Descendants("Expense");
            XElement firstRow = rows.First();

            firstRow.AddBeforeSelf(new XElement("Expense",
                   new XElement("Id", exp.Id.ToString()),
                   new XElement("Amount", exp.Amount.ToString()),
                   new XElement("Contact", exp.Contact),
                   new XElement("Description", exp.Description),
                   new XElement("Datetime", exp.Datetime)));
            xDocument.Save(filepath);
        }
    }
}
person Crowcoder    schedule 10.05.2019