Многопоточность C# — вызывает без управления

Необходимо реализовать грязные чтения.

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

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

Это может дать Вам так называемые "фантомные чтения", который является, когда Ваш запрос реагирует на данные из транзакции, которая не фиксировалась.

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

грязные чтения Использования. Вы правы в этом, они не дадут Вам идеальную точность, но они должны разрешить Ваши мертвые проблемы блокировки.

, Без которого, мы должны были бы обернуть каждый вызов LINQ, который мы выполняем (хорошо, простые чтения, который является подавляющим большинством их) в блоке кода транзакции строки 3-4, который является ужасен

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

17
задан colithium 15 November 2009 в 23:30
поделиться

6 ответов

Посмотрите на класс AsyncOperation . Вы создаете экземпляр AsyncOperation в потоке, в котором хотите вызвать обработчик, с помощью метода AsyncOperationManager.CreateOperation . Аргумент, который я использую для Create , обычно имеет значение null, но вы можете установить его любое значение. Чтобы вызвать метод в этом потоке, используйте метод AsyncOperation.Post .

18
ответ дан 30 November 2019 в 12:00
поделиться

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

1
ответ дан 30 November 2019 в 12:00
поделиться

Используйте SynchronizationContext.Current , который будет указывать на то, с чем вы можете синхронизироваться.

Это будет делать правильные вещи ™ в зависимости от тип приложения. Для приложения WinForms он будет запускать это в основном потоке пользовательского интерфейса.

В частности, используйте метод SynchronizationContext.Send , например:

SynchronizationContext context =
    SynchronizationContext.Current ?? new SynchronizationContext();

context.Send(s =>
    {
        // your code here
    }, null);
13
ответ дан 30 November 2019 в 12:00
поделиться

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

Опять же, только те элементы управления пользовательского интерфейса, которые вы хотите обновить, должны быть вызваны, чтобы сделать их потокобезопасными. Некоторое время назад я написал в блоге запись о « Простом решении для незаконных вызовов между потоками в C # »

В этом сообщении содержится более подробная информация, но суть очень простого (но ограниченного) подхода заключается в использовании функции анонимного делегата в элементе управления пользовательского интерфейса, который вы хотите обновить:

if (label1.InvokeRequired) {
  label1.Invoke(
    new ThreadStart(delegate {
      label1.Text = "some text changed from some thread";
    }));
} else {
  label1.Text = "some text changed from the form's thread";
}

Надеюсь, это поможет. InvokeRequired технически необязателен,

2
ответ дан 30 November 2019 в 12:00
поделиться

Если вы используете WPF:

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

Самый простой способ получить диспетчер - использовать Application.Current.Dispatcher. Это диспетчер, отвечающий за основной (и, вероятно, единственный) поток пользовательского интерфейса.

Собираем все вместе:

class MyClass
{
    // Can be called on any thread
    public ReceiveLibraryEvent(RoutedEventArgs e)
    {
        if (Application.Current.CheckAccess())
        {
            this.ReceiveLibraryEventInternal(e);
        }
        else
        {
            Application.Current.Dispatcher.Invoke(
                new Action<RoutedEventArgs>(this.ReceiveLibraryEventInternal));
        }
    }

    // Must be called on the UI thread
    private ReceiveLibraryEventInternal(RoutedEventArgs e)
    {
         // Handle event
    }
}
1
ответ дан 30 November 2019 в 12:00
поделиться

Есть ли способ обойти это?

Да, обходной путь для вас будет заключаться в создании потокобезопасной очереди.

  • Обработчик событий вызывается третьим- party thread
  • Ваш обработчик событий ставит что-то (данные события) в очередь в коллекцию (например, список), которой вы владеете.
  • Ваш обработчик событий делает что-то, чтобы сигнализировать вашему собственному thead, что в коллекции есть данные, которые нужно исключить из очереди и процесс:
    • Ваш поток может чего-то ждать (мьютекс или что-то еще); когда его мьютекс сигнализируется обработчиком событий, он просыпается и проверяет очередь.
    • В качестве альтернативы, вместо того, чтобы получать сигнал, он может периодически просыпаться (например, раз в секунду или что-то еще) и опрашивать очередь.

В В любом случае, поскольку ваша очередь записывается двумя разными потоками (сторонний поток ставится в очередь, а ваш поток удаляется из очереди), она должна быть потокобезопасной, защищенной очередью.

0
ответ дан 30 November 2019 в 12:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: