Выполните некоторую операцию после завершения потока - PullRequest
1 голос
/ 17 декабря 2009

Приветствую всех!

У меня есть класс (скажем, «Switcher»), который выполняет очень-очень долгую операцию и уведомляет своего слушателя, что операция завершена. Операция длинная, и я выделяю фактическое переключение в отдельный поток:

class Switcher
{
public:
    // this is what other users call:
    void StartSwitching()
    {
        // another switch is initiated, I must terminate previous switching operation:
        if ( m_Thread != NULL )
        {
            if ( WaitForThread(m_Thread, 3000) != OK ) 
            {
                TerminateThread(m_Thread);
            }
        }
        // start new switching thread:
        m_Thread = StartNewThread( ThreadProc );
    }

    // this is a thread procedure:
    static void ThreadProc()
    {
        DoActualSwitching();
        NotifyListener();
    }

private:
    Thread m_Thread;
};

Логика довольно проста - если пользователь инициирует новое переключение до завершения предыдущего, я прекращаю предыдущее переключение (не обращая внимания на то, что происходит внутри "DoActualSwitching ()") и запускаю новое. Проблема в том, что иногда при завершении потока я теряю вызов NotifyListener ().

Я хотел бы внести некоторые улучшения, чтобы гарантировать, что NotifyListener () вызывается каждый раз, даже если поток завершается. Есть ли шаблон для этого? Я могу думать только о другом потоке, который бесконечно ждет коммутатора и, если коммутатор выполнен (правильно или по завершении), он может выдать уведомление. Но знакомство с другой темой для меня кажется излишним. Можете ли вы придумать какое-либо другое решение (например, платформа win32)?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 17 декабря 2009

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

Чтобы ваш поток был прерываемым / отменяемым, вы указываете состояние отмены, которое проверяется самим потоком. Тогда ваш конец уведомления всегда будет работать.

1 голос
/ 17 декабря 2009

TerminateThread () здесь удаляет поток, и если он был внутри DoActualSwitching (), то там он и умрет, и NotifyListener () не будет вызываться в этом потоке Это то, что делает TerminateThread (), и нет способа заставить его вести себя иначе.

То, что вы ищете, является более изящным способом завершить поток. Без дополнительной информации о вашем приложении трудно предложить оптимальный подход, но если вы сможете редактировать DoActualSwitching (), я бы добавил

if (WAIT_OBJECT_0 == WaitForSingleObject(m_ExitThreadEvent, 0))
    break;

в цикл и вызовите SetEvent (m_ExitThreadEvent) вместо TerminateThread (). Конечно, вам нужно создать событие и добавить дескриптор класса. Если ваша модель предполагает, что одновременно существует только один поток переключения, я бы использовал здесь событие автоматического сброса, в противном случае потребуется еще немного кода.

Удачи!

...