Я подумал, что я должен обобщить некоторые обсуждения в комментариях в ответ.
В программировании Windows вы никогда не должны пытаться манипулировать элементом управления GUI из фонового потока, так как это может привести к блокировке вашей программы. Это означает, что только основной поток должен когда-либо касаться элементов GUI. (Технически важно то, какой поток создал элемент управления, но не принято создавать элементы управления в фоновых потоках).
Это требование подробно описано в статье Джо Ньюкомера о рабочих потоках (см. «Рабочие потоки и графический интерфейс II: не прикасайтесь к графическому интерфейсу»).
Вы используете SendMessage
в своих процедурах потока. Это вызывает соответствующий обработчик сообщений для целевого элемента управления, но в потоке, который вызвал SendMessage
. В вашем случае это означает, что фоновые потоки запускают обработчики сообщений и, следовательно, обновляют индикатор выполнения и метку.
Альтернатива - использовать PostMessage
. Это приводит к тому, что сообщение, добавляемое в очередь, обрабатывается в цикле сообщений основного потока. Когда основной поток запускается, он обрабатывает сообщения в порядке их добавления в очередь, вызывая сами обработчики сообщений. Поскольку основной поток владеет окнами, безопасно обновлять элементы управления.
Вам также следует помнить, что SuspendThread
и ResumeThread
сложно сделать правильно. Возможно, вы захотите прочитать этот раздел статьи Джо Ньюкомера, в которой описаны некоторые опасности.
Такие задачи часто лучше достигаются с помощью таймера . Это механизм для того, чтобы операционная система уведомляла вашу программу, когда прошло определенное время. Вы можете реализовать это с помощью таймера, как показано ниже:
BEGIN_MESSAGE_MAP(CThreadingEx3Dlg, CDialog)
ON_WM_DESTROY()
ON_WM_TIMER()
END_MESSAGE_MAP()
void CThreadingEx3Dlg::OnTimer(UINT_PTR nTimerID)
{
static int progress = 0;
if (nTimerID == 1)
{
m_ProgressBar.SetPos(progress);
CString strStatus;
strStatus.Format(_T("Processing item: %d"), progress);
m_Static.SetWindowText(strStatus);
progress++;
if (progress > end) // If we've reached the end of the updates.
KillTimer(1);
}
}
BOOL CThreadingEx3Dlg::OnInitDialog()
{
// ... initialize controls, etc, as necessary.
SetTimer(1, 100, 0);
}
void CThreadingEx3Dlg::OnDestroy()
{
KillTimer(1);
}
Если вы хотите, чтобы оба обновления обрабатывались одновременно, они могут использовать один и тот же таймер. Если они должны происходить в разное время (например, один с интервалом в 100 мс, а другой с интервалом в 150 мс), вы можете дважды вызвать SetTimer
с разными идентификаторами. Чтобы приостановить действие, позвоните KillTimer
. Для возобновления звоните снова SetTimer
.