Постарайтесь не звонить, Вызывают, когда управление расположено

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

Настолько самоосматривающий, самоизменяющий код мог быть записан легко.

27
задан Ozgur Ozcitak 9 December 2009 в 15:39
поделиться

6 ответов

В вашем коде есть неявные условия гонки. Элемент управления можно разместить между тестом IsDisposed и тестом InvokeRequired. Между InvokeRequired и Invoke () есть еще один. Вы не можете исправить это, не убедившись, что элемент управления переживет срок службы потока. Учитывая, что ваш поток генерирует данные для представления списка, он должен прекратить работу до того, как представление списка исчезнет.

Сделайте это, установив e.Cancel в событии FormClosing и сигнализируя потоку об остановке с помощью ManualResetEvent. Когда поток завершится, снова вызовите Form.Close (). Использование BackgroundWorker позволяет легко реализовать логику завершения потока, пример кода можно найти в этой публикации .

14
ответ дан 28 November 2019 в 05:17
поделиться

Вы можете использовать мьютексы.

Где-то в начале потока:

 Mutex m=new Mutex();

Затем:

if (mImageListView != null && 
    mImageListView.IsHandleCreated &&
    !mImageListView.IsDisposed)
{
    m.WaitOne(); 

    if (mImageListView.InvokeRequired)
        mImageListView.Invoke(
            new RefreshDelegateInternal(mImageListView.RefreshInternal));
    else
        mImageListView.RefreshInternal();

    m.ReleaseMutex();
}

И где бы вы ни находились, mImageListView удаляется:

 m.WaitOne(); 
 mImageListView.Dispose();
 m.ReleaseMutex();

Это должно гарантировать, что вы не можете удалить и вызвать в в то же время.

1
ответ дан 28 November 2019 в 05:17
поделиться

Одним из способов может быть еще один вызов самого метода вместо вызова ImageListView-Method:

if (mImageListView != null && 
    mImageListView.IsHandleCreated &&
    !mImageListView.IsDisposed)
{
    if (mImageListView.InvokeRequired)
        mImageListView.Invoke(new YourDelegate(thisMethod));
    else
        mImageListView.RefreshInternal();
}

Таким образом, он проверит еще раз перед окончательным вызовом RefreshInternal ().

0
ответ дан 28 November 2019 в 05:17
поделиться

Здесь имеется состояние гонки . Лучше просто перехватить исключение ObjectDisposed и покончить с этим. Фактически, я думаю, что в данном случае это единственное рабочее решение.

try
{
    if (mImageListView.InvokeRequired)
       mImageListView.Invoke(new YourDelegate(thisMethod));
    else
       mImageListView.RefreshInternal();
} 
catch (ObjectDisposedException ex)
{
    // Do something clever
}
19
ответ дан 28 November 2019 в 05:17
поделиться

См. Также этот вопрос:

Как избежать проблем с Invoke / BeginInvoke при межпотоковой обработке событий WinForm?

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

Настоящая проблема здесь в том, что nobugz прав, поскольку он указывает, что API-интерфейсы, предоставленные для межпоточных вызовов в winforms, по своей сути не являются потокобезопасными. Даже внутри самих вызовов InvokeRequired и Invoke / BeginInvoke есть несколько состояний гонки, которые могут вызвать непредвиденное поведение.

1
ответ дан 28 November 2019 в 05:17
поделиться

может быть заблокирован (mImageListView) {...}?

1
ответ дан 28 November 2019 в 05:17
поделиться
Другие вопросы по тегам:

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