C # параллелизм, блокировка и словарь объектов - PullRequest
0 голосов
/ 14 января 2009

У меня есть куча сущностей БД, которые загружаются в объекты БД. Одна и та же сущность БД может быть загружена не только в объект БД. Периодически объект БД будет требовать специальной обработки. Эта обработка должна выполняться одним потоком за раз. Блокировка в порядке здесь.

РЕДАКТИРОВАТЬ: Важное примечание: процесс вызывает медленный веб-сервис. Это то, что я пытаюсь предотвратить параллелизмом. Я не понимаю, как это можно безопасно сделать без замков.

Поэтому я создаю объект «навесной замок», на который будут ссылаться объекты БД для блокировки. Объект висячего замка основан на объектах, поэтому два или более объектов БД для одного и того же объекта будут использовать один и тот же объект висячего замка. Я храню эти замки в объекте словаря, используя в качестве ключа идентификатор сущности БД. Объект замка также является простым строковым объектом. Это правильный подход? Я думаю, что я или над разработкой или упрощением этого. Если подход правильный, как выглядит этот код? Это работает, но я еще не тестировал его под нагрузкой.

Спасибо:)

public static func(CustomObject o)
{
    if (ReadyForUpdate(o))
    {
        lock (LookupPadLockByID(object.ID)
        {
            if (ReadyForUpdate(o))
            {
                PerformUpdate(object);
            }
        }
    }
}

private static readonly object padlockLock = new object();
private static readonly Dictionary<int, string> padLocks = new Dictionary<int,string>();
private static object LookupPadLockByID(int uniqueID)
{
    lock (padlockLock)
    {
        if (!padLocks.ContainsKey(uniqueID))
        {
            padLocks.Add(uniqueID, uniqueID + " is locked");
        }
    }

    return padLocks[uniqueID];
}

Ответы [ 4 ]

1 голос
/ 14 января 2009

Блокировка строки не очень хорошая идея. Я предлагаю две альтернативы:

  1. Используйте Dictionary<int,object> в качестве типа padLocks и укажите new object(); в качестве значения.
  2. Создать класс, который просто содержит идентификатор; это было бы лучше для удобства чтения, если вы когда-нибудь захотите посмотреть на свой класс LockPad во время отладки.

Класс LockPad:

class LockPad {
    public int Id { get; private set; }

    public LockPad(int id) {
        this.Id = id;
    }

    public override string ToString() {
        return "lock of " + id.ToString();
    }
}

Затем заблокируйте этот класс.

1 голос
/ 14 января 2009

Что ж, вы в конечном итоге блокируете строку, что не очень хорошая идея (хотя объединение означает, что интернирование не должно быть большой проблемой). Что более важно, так это:

  • вы, кажется, не снимаете блокировки с padLocks - это проблема?
  • вы получаете доступ к словарю за пределами padlockLock; return должен быть внутри lock

Для этой секунды это будет проще:

object itemLock;
if (!padLocks.TryGetValue(uniqueID, out itemLock)) {
    itemLock = new object();
    padLocks.Add(uniqueID, itemLock);
}
return itemLock;

Если этот код достаточно локальный (т. Е. Ваши объекты еще не экранированы), вы могли бы просто lock сама запись? Намного проще ...

0 голосов
/ 14 января 2009

Если вы используете стандартную базу данных любого типа, я бы предложил полностью сбросить эти блокировки на стороне клиента в пользу транзакций и блокировок таблицы / строки.

0 голосов
/ 14 января 2009

Я думаю, ты закончил разработку. Если вам нужно только защитить сущности вашей БД (которые, как я полагаю, представлены в вашем коде «объектом», который я заменю на «сущность»), вы можете просто использовать его в качестве блокировки. Любой ссылочный объект может быть использован в качестве блокировки:

public static func(CustomObject o)
{
    if (ReadyForUpdate(o))
    {
        lock (entity)
        {
                if (ReadyForUpdate(o))
                {
                        PerformUpdate(entity);
                }
        }
    }
}
...