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

private void Thread1_Exe()
{
    try
    {
        int sleepValT1 = Convert.ToInt32(listBoxT2.SelectedValue);
        int StartLoop = 0;
        int EndLoop = 10000;

        for (int i = StartLoop; i <= EndLoop; i++)
        {
            Dispatcher.BeginInvoke(
            new Action(() => listboxE1.Items.Add("T1: Execution Count> " + i.ToString())));
            Thread.Sleep(sleepValT1);
        }

    }
    catch (Exception Ex)
    {
        MessageBox.Show(Ex.Message);
    }
}

Я пытался вызвать вышеуказанную функцию в другом потоке

private void thread1_Click(object sender, RoutedEventArgs e)
{
    threadBtn1.IsEnabled = false;
    Thread t1 = new Thread(new ThreadStart(Thread1_Exe));

    t1.Start();
}

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

Thread.Sleep()

Я всегда получаю это исключение, что другой поток владеет этим объектом. Перепробовал много вещей. Пожалуйста, помогите мне, где я делаю ошибку.

Спасибо

2 ответа

Решение

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

Самое простое, что вы можете сделать, это прочитать значение из списка, прежде чем запускать новый поток:

private void Thread1_Exe(int sleepVal)
{
    try
    {
        int StartLoop = 0;
        int EndLoop = 10000;


        for (int i = StartLoop; i <= EndLoop; i++)
        {

            Dispatcher.BeginInvoke(
            new Action(() =>
            listboxE1.Items.Add("T1: Execution Count> " + i.ToString())));
            Thread.Sleep(sleepVal);
        }

    }
    catch (Exception Ex)
    {
        MessageBox.Show(Ex.Message);
    }
}

private void thread1_Click(object sender, RoutedEventArgs e)
{

    threadBtn1.IsEnabled = false;

    int sleepValT1 = Convert.ToInt32(listBoxT1.SelectedValue);
    Thread t1 = new Thread(() => Thread1_Exe(sleepValT1));

    t1.Start();
}

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

private void Thread1_Exe()
{
    try
    {
        int sleepValT1;
        listBoxT1.Dispatcher.Invoke(() => sleepValT1 = Convert.ToInt32(listBoxT1.SelectedValue));
        int StartLoop = 0;
        int EndLoop = 10000;


        for (int i = StartLoop; i <= EndLoop; i++)
        {

            Dispatcher.BeginInvoke(
            new Action(() =>
            listboxE1.Items.Add("T1: Execution Count> " + i.ToString())));
            Thread.Sleep(sleepValT1);
        }

    }
    catch (Exception Ex)
    {
        MessageBox.Show(Ex.Message);
    }
}

private void thread1_Click(object sender, RoutedEventArgs e)
{

    threadBtn1.IsEnabled = false;

    Thread t1 = new Thread(() => Thread1_Exe());

    t1.Start();
}

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

Любой доступ к GUI элемент, независимо от того, читается он или пишется, должен называться через main-UI-thread, Эта тема доступна через Dispatcher,

В вашем коде я вижу строку, где это не так - когда вы звоните listBoxT2.SelectedValue

Чтобы исправить ошибку, назовите этот код на Dispatcher Thread и сохраните его в локальной переменной:

int selectedValue;
listBoxT2.Dispatcher.Invoke(() => selectedValue = Convert.ToInt32(listBoxT2.SelectedValue));

Остальная часть кода должна работать нормально.

Другие вопросы по тегам