2010-09-03 7 views
0

Этот вопрос, вероятно, задавался по-разному раньше, но вот что я хочу сделать. У меня будет форма Windows со многими вкладками. Каждая вкладка будет содержать объект сетки. Для каждой вкладки/сетки, созданной пользователем, я хотел бы, чтобы всплыл выделенный поток, чтобы заполнить содержимое этой сетки постоянно поступающей информацией. Может ли кто-нибудь привести пример того, как сделать это безопасно?Вопрос с базовым вопросом

Спасибо.

+0

Мы говорим о WinForms или WPF? – Arcturus

+0

@Arcturus - WinForms –

+0

Это .Net 4 или более ранняя версия? – Ragoczy

ответ

3

Внутри инициализации на вкладке (при условии, WinForms, пока я не вижу иначе):

Thread newThread = new Thread(() => 
{ 
    // Get your data 

    dataGridView1.Invoke(new Action(() => { /* add data to the grid here */ }); 
}); 

newThread.Start(); 

То есть, очевидно, самый простой пример. Вы также можете порождать потоки с помощью ThreadPool (который чаще всего выполняется в серверных приложениях).

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

+1

Моей заботой в этом подходе было бы количество потоков и объем работы, которые каждый должен делать. ОП указывает «много» вкладок - слишком много вкладок со слишком большой работой, чтобы сделать это может привести к значительным избиениям, что на самом деле повредит производительности. ThreadPool справится с этим, и TPL справится с этим еще лучше. – Ragoczy

+0

@Ragoczy - Именно поэтому я упоминаю, что это был самый простой пример, и OP, вероятно, должен проверить ThreadPool и TPL (если он доступен для него). –

+0

Спасибо за ваши комментарии. Я сомневаюсь, что у любого пользователя было бы одновременно открыто более 3-5 вкладок. Это было бы самым большим. –

0

Вы должны иметь массив потоков, чтобы иметь возможность контролировать их

List<Thread> tabs = new List<Thread>(); 

...

Чтобы добавить новый, будет, как:

tabs.Add(new Thread(new ThreadStart(TabRefreshHandler)); 
//Now starting: 
tabs[tabs.Count - 1].Start(); 

И наконец, в TabRefreshHandler вы должны проверить, какой номер вызывающего потока, и вы будете знать, какая вкладка должна быть обновлена!

+0

Как вы планируете контролировать потоки через список (вопрос любопытства)? –

+0

Его очень легко, если вы хотите остановить Tab3 от обновления, вы должны остановить Thread в третьем слоте списка, так как они должны быть добавлены в одно и то же время, идея состоит в том, чтобы иметь отношение между номером потока в списке и номер вкладки. Вы также можете использовать HashTable для сохранения имени вкладки. Я думаю, что этот способ даст вам больше контроля в обновлениях. –

+0

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

1

Существует два основных подхода, которые вы можете использовать. Выберите тот, который имеет наибольший смысл в вашей ситуации. Часто нет правильного или неправильного выбора. Они могут работать одинаково хорошо во многих ситуациях. У каждого свои преимущества и недостатки. Как ни странно, сообщество, похоже, слишком часто пропускает метод pull. Я не уверен, почему это так. Я недавно наткнулся на вопрос this, в котором каждый рекомедовал подход «подталкивания», несмотря на то, что он был идеальной ситуацией для метода выталкивания (была одна бедная душа, которая шла против стада и забиралась вниз и, в конце концов, удаляла свой ответ, оставив только меня в качестве одиночного диссидента).

Нажмите Метод

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

void WorkerThread() 
{ 
    while (true) 
    { 
    object data = GetNewData(); 
    yourForm.Invoke(
     (Action)(() => 
     { 
     // Add data to your grid here. 
     })); 
    } 
} 

Прицепного Метод

Есть поток пользовательского интерфейса вытащить данные из рабочего потока. У вас будет рабочий поток, в который вносятся новые элементы данных в общую очередь, а поток пользовательского интерфейса будет периодически деактивировать элементы. Преимущество в том, что вы можете дросселировать объем работы, каждый поток выполняет независимо. Очередь - это ваш буфер, который будет уменьшаться и увеличиваться по мере того, как потребление ресурсов и потоки процессора. Он также отделяет логику рабочего потока от потока пользовательского интерфейса. Недостаток заключается в том, что если ваш поток пользовательского интерфейса не будет опробовать достаточно быстро или продолжит рабочий поток, он может перегрузить очередь. И, конечно, элементы данных не появятся в реальном времени в вашей сетке. Однако, если вы установите интервал System.Windows.Forms.Timer достаточно коротким, чтобы не быть проблемой для вас.

private Queue<object> m_Data = new Queue<object>(); 

private void YourTimer_Tick(object sender, EventArgs args) 
{ 
    lock (m_Data) 
    { 
    while (m_Data.Count > 0) 
    { 
     object data = m_Data.Dequeue(); 
     // Add data to your grid here. 
    } 
    } 
} 

void WorkerThread() 
{ 
    while (true) 
    { 
    object data = GetNewData(); 
    lock (m_Data) 
    { 
     m_Data.Enqueue(data); 
    } 
    } 
} 
+0

Хороший ответ. По моему опыту, метод вытаскивания - это почти всегда лучший подход к программному обеспечению качества продукции. –

+0

@ Dan: Да, это удивительно, как часто его пропускают. Моя теория заключается в том, что это эффект стада. Как только идея засаживается и развивается критическая масса, она снимается, а все остальное игнорируется и списывается без должной дилемности. –

Смежные вопросы