Сделать коллекцию доступной для двух процессов - PullRequest
2 голосов
/ 13 декабря 2011

Привет, ребята, у меня есть словарь, который должен быть разделен между двумя различными исполняемыми файлами. Первое приложение создает ключ, затем сохраняет его в словаре, затем другое приложение создает ключ и сохраняет его в словаре.

На данный момент я делаю это:

private static void WriteToFile(Dictionary<string, byte[]> dictionary, string path)
    {
        Contract.Requires(dictionary != null);
        Contract.Requires(!string.IsNullOrEmpty(path));

        if (!(timestamp == File.GetLastWriteTime(DatabasePath)))
        {
            using (FileStream fs = File.OpenWrite(path))
            using (var writer = new BinaryWriter(fs))
            {
                // Put count.
                writer.Write(dictionary.Count);

                // Write pairs.
                foreach (var pair in dictionary)
                {
                    writer.Write(pair.Key);
                    writer.Write(pair.Value);
                }
                timestamp = DateTime.Now;
                File.SetLastWriteTime(DatabasePath, timestamp);

            }
        }
    }

    /// <summary>
    /// This is used to read a dictionary from a file
    /// http://www.dotnetperls.com/dictionary-binary
    /// </summary>
    /// <param name="path">The path to the file</param>
    /// <returns>The dictionary read from the file</returns>
    private static Dictionary<string, byte[]> ReadFromFile(string path)
    {
        Contract.Requires(!string.IsNullOrEmpty(path));
        var result = new Dictionary<string, byte[]>();
        using (FileStream fs = File.OpenRead(path))
        using (var reader = new BinaryReader(fs))
        {
            // Determine the amount of key value pairs to read.
            int count = reader.ReadInt32();

            // Read in all the pairs.
            for (int i = 0; i < count; i++)
            {
                string key = reader.ReadString();
                //// The byte value is hardcoded as the keysize is consistent
                byte[] value = reader.ReadBytes(513);
                result[key] = value;
            }
        }
        return result;
    }

Затем, когда я хочу сохранить ключ, я вызываю этот метод:

public static bool StoreKey(byte[] publicKey, string uniqueIdentifier)
    {
        Contract.Requires(ValidPublicKeyBlob(publicKey));
        Contract.Requires(publicKey != null);
        Contract.Requires(uniqueIdentifier != null);
        Contract.Requires(uniqueIdentifier != string.Empty);
        bool success = false;

        if (File.Exists(DatabasePath))
        {
            keyCollection = ReadFromFile(DatabasePath);
        }

        if (!keyCollection.ContainsKey(uniqueIdentifier))
        {
            if (!keyCollection.ContainsValue(publicKey))
            {
                keyCollection.Add(uniqueIdentifier, publicKey);
                success = true;

                WriteToFile(keyCollection, DatabasePath);
            }
        }
        return success;
    }

Когда программы генерируют ключ и когда мы пытаемся получить к ним доступ, он имеет только 1 ключ, что я делаю не так? Ключ и строка хранятся отлично, но я просто боюсь, что они перезаписывают файлы или что-то в этом роде.

Большое спасибо заранее, любая помощь очень ценится

PS: databasePath - это путь, по которому я хочу сохранить файл, созданный в виде поля.

Ответы [ 3 ]

3 голосов
/ 13 декабря 2011

Трудно сказать, что именно происходит, поскольку вы не предоставили информацию о количестве элементов в словаре и т. Д., Но, похоже, вы столкнулись с какой-то проблемой доступа к файлу при доступе к тому же файлу из нескольких процессов.

Вы можете использовать именованный Mutex в качестве объекта межпроцессной синхронизации, поэтому перед доступом к файлу необходимо убедиться, что дескриптор Mutex освобожден, чтобы вы могли получить право собственности, а другой процесс мог ждать до того, как доступ к файлу.

// Create a mutex
Mutex mutex = new Mutex(false, "DictionaryAccessMutex");

// Acquire an ownership
mutex.WaitOne();

// Release
mutex.ReleaseMutex();

РЕДАКТИРОВАТЬ: Новая находка

Также вы пытаетесь писать сразу после чтения, поэтому, возможно, операция FileSystem еще не завершена, поэтому запись не удалась, я не уверен, что 100% в этом, возможно, .NET-управляемых классах, таких как File / StreamReader / etc, уже обрабатывали такие случаи, но Я считаю, что в вашем случае стоит перепроверить, так как не ясно на 100%, что произошло. Поэтому попробуйте добавить некоторое время ожидания, например Thread.Sleep(500), между операциями чтения и записи.

РЕДАКТИРОВАТЬ: Еще одна вещь, которую вы можете сделать, это загрузить Утилита Process Monitor SysInternals и посмотреть, какие операции не были выполнены при доступе к данному файлу. Так что просто добавьте новый фильтр Path=file name, и вы сможете увидеть, что происходит на низком уровне.

2 голосов
/ 13 декабря 2011

Запись в файл параллельно, как правило, не лучшая идея. У вас есть два варианта здесь:

  1. Используйте мьютекс для межпроцессной синхронизации, чтобы регулировать доступ к файлу.
  2. Переадресация всех запросов на запись третьему процессу, который имеет исключительное право собственности на файл и выполняет фактическую запись.
0 голосов
/ 13 декабря 2011

Итак, процесс 1 загружает словарь, добавляет элемент, вызывает запись.Таким образом, процесс 2 загружает словарь, добавляет элемент, вызывает запись.

Вы получаете то, что когда-либо пишет в секунду, и вы не знаете, какой это будет.

Пытаясь сделать эторабота - это гораздо больше хлопот, чем она того стоит, и она будет такой же надежной в будущем, как и надувной дартс.

Мьютекс одним нажатием или третий процесс для поддержания словаря.

...