首页 > 解决方案 > 如何正确允许多个任务访问数据库文件?

问题描述

我有一个服务器,它接受多个客户端请求作为需要从 Microsoft Access .mdb 数据库文件读取和写入的多个任务。我想当他们将 EnqueueWriteCommand 和 EnqueueReadCommand 作为任务调用时,我会让服务器排队操作,然后让另一个单独运行的任务 (ExecuteTasks) 运行排队的任务。这个想法感觉非常复杂,但我似乎找不到或想出更好的方法来做到这一点。下面是我的代码。

根据我的测试,当我调用“await Task.Run(() => task)”时,ExecuteTasks 中似乎出现了死锁。

是什么导致了这种僵局?在用多线程解决这个问题时,我的一般想法是否正确?有一个更好的方法吗?

using System.Data.OleDb;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Diagnostics;

namespace appDatabaseConsole

{
/// <summary>
/// Contains all necessary components for initializing and interacting with 
    the database file.
/// </summary>
public static class DBHandler
{
    private static OleDbConnection c;
    private static OleDbDataReader reader;
    private static OleDbCommand command;

    private static List<Task> tasks;

    /// <summary>
    /// Initialize the connection of the OleDbConnection components to the database file.
    /// </summary>d
    public static void InitializeConnection()
    {
        c = new OleDbConnection
        {
            ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\\AppDatabase.mdb"
        };
        command = new OleDbCommand
        {
            Connection = c
        };
        reader = null;

        tasks = new List<Task>();

        // Run the Task executor ask a separate task
        Task.Run(() => ExecuteTasks());
    }

    private async static Task ExecuteTasks()
    {
        while (true)
        {
            if (tasks.Count > 0)
            {
                Debug.WriteLine("tasks.Count exceeded zero");
                foreach (Task task in tasks)
                {
                    await Task.Run(() => task);
                    tasks.Remove(task);
                    Debug.WriteLine("Completed task and removed task.");
                }
            }
        }
    }

    public static void EnqueueWriteCommand(string commandText)
    {
        Debug.WriteLine("Start EnqueueWriteCommand");
        Task task = new Task(() => WriteCommand(commandText));
        tasks.Add(task);
        Debug.WriteLine("Finish EnqueueWriteCommand");
    }

    public static List<string>[] EnqueueReadCommand(string commandText, int numberOfColumns)
    {
        Debug.WriteLine("Start EnqueueReadCommand");
        Task<List<string>[]> task = new Task<List<string>[]>(() => ReadCommand(commandText, numberOfColumns));
        tasks.Add(task);

        Debug.WriteLine("Just before finishing EnqueueReadCommand");
        return task.Result;
    }

    private static void WriteCommand(string commandText)
    {
        Debug.WriteLine("Start WriteCommand");
        c.Open();
        command.CommandText = commandText;
        command.ExecuteNonQuery();
        c.Close();
        Debug.WriteLine("Finish WriteCommand");
    }

    private static List<string>[] ReadCommand(string commandText, int numberOfColumns)
    {
        Debug.WriteLine("Start ReadCommand");
        c.Open();
        command.CommandText = commandText;
        reader = command.ExecuteReader();

        List<string>[] data = new List<string>[numberOfColumns];
        for (int column = 0; column < numberOfColumns; column++)
        {
            while (reader.Read())
            {
                data[column].Add(reader[column].ToString());
            }
        }
        reader.Close();
        c.Close();
        Debug.WriteLine("Finish ReadCommand");
        return data;
    }
}

}

标签: c#.netasynchronoustask

解决方案


推荐阅读