SetConsoleCtrlHandler и многопоточность
От: mityaj.it.0  
Дата: 18.09.09 09:19
Оценка:
Привет всем, есть такой код:
BOOL ConsoleHandler( DWORD fdwCtrlType )
{
    switch (fdwCtrlType) {
        case CTRL_C_EVENT: {
            std::cout << "Exit." << "\n";
                        exit(1);
        }

    }
}
int _tmain(int argc, _TCHAR* argv[])
    if (SetConsoleCtrlHandler( (PHANDLER_ROUTINE)ConsoleHandler,TRUE)==FALSE) {
        // unable to install handler... 
        return -1;
    }
    try {
        // Enable exceptions in cin.
        std::cin.exceptions(std::ios::badbit|std::ios::failbit);
        int itSum = 0;
        std::cin >> itSum;
    catch (...) {
        std::cout << "Error!" << "\n";
    }
}

Необходимо при ожидании ввода числа иметь возможность завершить программу по нажатию [Ctrl+C]. Данный код
это предоставляет, но с одним "НО": обработчик ConsoleHandler вызывается в другом потоке и основной поток также продолжает выполнение.
В итоге выполняется обработчик исключения и обработчик [Ctrl+C]. Это некорректно. Каким образом затормозить основной поток или
дать ему понять, что нажата [Ctrl+C]?


23.09.09 20:26: Перенесено модератором из 'C/C++. Прикладные вопросы' — Кодт
Re: SetConsoleCtrlHandler и многопоточность
От: Аноним  
Дата: 18.09.09 09:33
Оценка:
Здравствуйте, mityaj.it.0, Вы писали:

MI0>Привет всем, есть такой код:

MI0>
MI0>BOOL ConsoleHandler( DWORD fdwCtrlType )
MI0>{
MI0>    switch (fdwCtrlType) {
MI0>        case CTRL_C_EVENT: {
MI0>            std::cout << "Exit." << "\n";
MI0>                        exit(1);
MI0>        }

MI0>    }
MI0>}
MI0>int _tmain(int argc, _TCHAR* argv[])
MI0>    if (SetConsoleCtrlHandler( (PHANDLER_ROUTINE)ConsoleHandler,TRUE)==FALSE) {
MI0>        // unable to install handler... 
MI0>        return -1;
MI0>    }
MI0>    try {
MI0>        // Enable exceptions in cin.
MI0>        std::cin.exceptions(std::ios::badbit|std::ios::failbit);
MI0>        int itSum = 0;
MI0>        std::cin >> itSum;
MI0>    catch (...) {
MI0>        std::cout << "Error!" << "\n";
MI0>    }
MI0>}

MI0>

MI0>Необходимо при ожидании ввода числа иметь возможность завершить программу по нажатию [Ctrl+C]. Данный код
MI0>это предоставляет, но с одним "НО": обработчик ConsoleHandler вызывается в другом потоке и основной поток также продолжает выполнение.
MI0>В итоге выполняется обработчик исключения и обработчик [Ctrl+C]. Это некорректно. Каким образом затормозить основной поток или
MI0>дать ему понять, что нажата [Ctrl+C]?

Используйте средства синхронизации, можно посмотреть здесь — http://msdn.microsoft.com/ru-ru/library/172d2hhw.aspx
Re[2]: SetConsoleCtrlHandler и многопоточность
От: mityaj.it.0  
Дата: 18.09.09 11:56
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Используйте средства синхронизации, можно посмотреть здесь — http://msdn.microsoft.com/ru-ru/library/172d2hhw.aspx
Синхронизация мне не поможет. Мне нужно чтобы обработчик исключения мог узнать о событии [Ctrl+C]. А получается так, что он
сначала выполняется, а потом только в другом потоке выполняется обработчик события [Ctrl+C]. Можно создать событие, кот. будет дергать обработчик
события [Ctrl+C] и подождать(где нить 500 мс) его в обработчике исключения, но это уже криво будет.

HANDLE hConsoleEvent = NULL;

int _tmain(int argc, _TCHAR* argv[]) {
...
hConsoleEvent = CreateEvent(NULL, true, false, NULL);
...
catch (...) {
if (WaitForSingleObject(hConsoleEvent, 500) == WAIT_TIMEOUT)
 std::cout << "Error!" << "\n";
else {
// нажали [Ctrl+C]
}
}


BOOL ConsoleHandler( DWORD fdwCtrlType )
{
SetEvent(hConsoleEvent);
...
}
Re[3]: SetConsoleCtrlHandler и многопоточность
От: Сергей Мухин Россия  
Дата: 18.09.09 12:01
Оценка:
Здравствуйте, mityaj.it.0, Вы писали:

MI0>Здравствуйте, Аноним, Вы писали:

А>>Используйте средства синхронизации, можно посмотреть здесь — http://msdn.microsoft.com/ru-ru/library/172d2hhw.aspx
MI0>Синхронизация мне не поможет. Мне нужно чтобы обработчик исключения мог узнать о событии [Ctrl+C]. А получается так, что он
MI0>сначала выполняется, а потом только в другом потоке выполняется обработчик события [Ctrl+C]. Можно создать событие, кот. будет дергать обработчик
MI0>события [Ctrl+C] и подождать(где нить 500 мс) его в обработчике исключения, но это уже криво будет.

Я один раз сделал очень грубо. в Thread захватил контекст главного thread и выставил свой IP.

Это чрезвычайно опасно, но обычно работает
---
С уважением,
Сергей Мухин
Re[4]: SetConsoleCtrlHandler и многопоточность
От: Аноним  
Дата: 19.09.09 11:33
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:
...
СМ>Я один раз сделал очень грубо. в Thread захватил контекст главного thread и выставил свой IP.

СМ>Это чрезвычайно опасно, но обычно работает


Хм... Такой подход должен быть соответственно прокомментирован в коде... Но это не вяжется с вашей подписью =)
Re[5]: SetConsoleCtrlHandler и многопоточность
От: Сергей Мухин Россия  
Дата: 19.09.09 19:34
Оценка:
Здравствуйте, Аноним, Вы писали:

СМ>>Я один раз сделал очень грубо. в Thread захватил контекст главного thread и выставил свой IP.


СМ>>Это чрезвычайно опасно, но обычно работает


А>Хм... Такой подход должен быть соответственно прокомментирован в коде... Но это не вяжется с вашей подписью =)


Что комментировать?
Если написано Context->Eip = myHandler;
Что тут пояснять?
---
С уважением,
Сергей Мухин
Re[6]: SetConsoleCtrlHandler и многопоточность
От: Аноним  
Дата: 20.09.09 05:25
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:

СМ>>>Я один раз сделал очень грубо. в Thread захватил контекст главного thread и выставил свой IP.


СМ>>>Это чрезвычайно опасно, но обычно работает


А>>Хм... Такой подход должен быть соответственно прокомментирован в коде... Но это не вяжется с вашей подписью =)


СМ>Что комментировать?

СМ>Если написано Context->Eip = myHandler;
СМ>Что тут пояснять?

СМ>чрезвычайно опасно, но обычно работает
Re[7]: SetConsoleCtrlHandler и многопоточность
От: Сергей Мухин Россия  
Дата: 20.09.09 18:01
Оценка:
Здравствуйте, Аноним, Вы писали:

СМ>>>>Это чрезвычайно опасно, но обычно работает


А>>>Хм... Такой подход должен быть соответственно прокомментирован в коде... Но это не вяжется с вашей подписью =)


СМ>>Что комментировать?

СМ>>Если написано Context->Eip = myHandler;
СМ>>Что тут пояснять?

чрезвычайно опасно, но обычно работает

1.
гм. Это ОЧЕВИДНО когда написано eip = ...
И зачем. Все равно этот комментарий не раскрывает причин, почему опасно и тп. А причины многочисленные и (на самом деле) довольно редки.
Описывать их все — тяжелая задача. Кстати, на самом деле я делал не только eip, там есть танцы с бубном, что бы повысить устойчивость еще на одну 9

2. это плохая программа, если надо так делать, как все известно, комментарии ее на спасут
---
С уважением,
Сергей Мухин
Re[8]: SetConsoleCtrlHandler и многопоточность
От: Аноним  
Дата: 20.09.09 20:02
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:

СМ>>>Что комментировать?

СМ>>>Если написано Context->Eip = myHandler;
СМ>>>Что тут пояснять?

СМ>чрезвычайно опасно, но обычно работает


СМ>1.

СМ>гм. Это ОЧЕВИДНО когда написано eip = ...
СМ>И зачем. Все равно этот комментарий не раскрывает причин, почему опасно и тп.

Я не до дословно имел ввиду : '//чрезвычайно опасно, но обычно работает', хотя даже это лучше чем ничего.

СМ>А причины многочисленные и (на самом деле) довольно редки.

СМ>Описывать их все — тяжелая задача.

Url/ссылка на книгу/статью... Хотя бы заострить на этом внимание. Пусть бы там было не 'Context->Eip = myHandler', а скажем 'service->reset()'. Да, возможно этот вызов раз в пятилетку приведет к плохому. Мне это так же ОЧЕВИДНО, как и вам про 'eip =', только дело не в этом — там любой код мог бы быть, про который можно сказать "опасно, но обычно работает"


СМ>2. это плохая программа, если надо так делать, как все известно, комментарии ее на спасут

Могут спасти... если все такие места будут помечены хотя бы чем-то вроде '// review' то как минимум их можно очень просто идентифицировать и потом предпринять какие-либо действия по исправлению. Почему их сразу не 'исправили'? А ф.з. причины могут быть разные... старый код с длинной историей и вереницей программистов, необходимость масштабного рефакторинга для исправления пары строк... Я согласен с тем, что лучше бы таких мест не было вообще, но при их наличии мы должны быть заинтересованы в их исправлении.
Re: SetConsoleCtrlHandler и многопоточность
От: Pavel Dvorkin Россия  
Дата: 21.09.09 06:13
Оценка:
Здравствуйте, mityaj.it.0, Вы писали:

MI0>Необходимо при ожидании ввода числа иметь возможность завершить программу по нажатию [Ctrl+C]. Данный код

MI0>это предоставляет, но с одним "НО": обработчик ConsoleHandler вызывается в другом потоке

А нельзя ли объяснить, откуда другой поток взялся. В приведенном коде я его упорно не вижу. При запуске программы (после того, как вставил две недостающие фигурные скобки), Task Manager говорит, что поток один. Откуда дровишки ?
With best regards
Pavel Dvorkin
Re[2]: SetConsoleCtrlHandler и многопоточность
От: Сергей Мухин Россия  
Дата: 21.09.09 06:14
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, mityaj.it.0, Вы писали:


MI0>>Необходимо при ожидании ввода числа иметь возможность завершить программу по нажатию [Ctrl+C]. Данный код

MI0>>это предоставляет, но с одним "НО": обработчик ConsoleHandler вызывается в другом потоке

PD>А нельзя ли объяснить, откуда другой поток взялся. В приведенном коде я его упорно не вижу. При запуске программы (после того, как вставил две недостающие фигурные скобки), Task Manager говорит, что поток один. Откуда дровишки ?


Когда управление передается handler'у по Ctrl+Cи тп — он работает на своем новом потоке.
---
С уважением,
Сергей Мухин
Re[9]: SetConsoleCtrlHandler и многопоточность
От: Сергей Мухин Россия  
Дата: 21.09.09 06:15
Оценка:
Здравствуйте, Аноним, Вы писали:


СМ>>1.

СМ>>гм. Это ОЧЕВИДНО когда написано eip = ...
СМ>>И зачем. Все равно этот комментарий не раскрывает причин, почему опасно и тп.

А>Я не до дословно имел ввиду : '//чрезвычайно опасно, но обычно работает', хотя даже это лучше чем ничего.

Вы дословно это написали, пишите что вы хотите сказать, что вы ДУМАЕТЕ понять из сообщение не возможно!

СМ>>А причины многочисленные и (на самом деле) довольно редки.

СМ>>Описывать их все — тяжелая задача.

А>Url/ссылка на книгу/статью... Хотя бы заострить на этом внимание. Пусть бы там было не 'Context->Eip = myHandler', а скажем 'service->reset()'. Да, возможно этот вызов раз в пятилетку приведет к плохому. Мне это так же ОЧЕВИДНО, как и вам про 'eip =', только дело не в этом — там любой код мог бы быть, про который можно сказать "опасно, но обычно работает"


ну вот я на той неделе потратил туеву хучу ввремени что бы найти ошибку в чужой программе. ошибка было (грубо говоря) a[i];
И помогли мне комментарии?

СМ>>2. это плохая программа, если надо так делать, как все известно, комментарии ее на спасут

А>Могут спасти... если все такие места будут помечены хотя бы чем-то вроде '// review' то как минимум их можно очень просто идентифицировать и потом предпринять какие-либо действия по исправлению. Почему их сразу не 'исправили'? А ф.з. причины могут быть разные... старый код с длинной историей и вереницей программистов, необходимость масштабного рефакторинга для исправления пары строк... Я согласен с тем, что лучше бы таких мест не было вообще, но при их наличии мы должны быть заинтересованы в их исправлении.

если все места будут помечены — идеализм.
---
С уважением,
Сергей Мухин
Re[2]: SetConsoleCtrlHandler и многопоточность
От: Pavel Dvorkin Россия  
Дата: 21.09.09 06:21
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>А нельзя ли объяснить, откуда другой поток взялся. В приведенном коде я его упорно не вижу. При запуске программы (после того, как вставил две недостающие фигурные скобки), Task Manager говорит, что поток один. Откуда дровишки ?


Да, проверил, верно, запускается новый поток.
With best regards
Pavel Dvorkin
Re[4]: SetConsoleCtrlHandler и многопоточность
От: mityaj.it.0  
Дата: 21.09.09 07:29
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:

СМ>Здравствуйте, mityaj.it.0, Вы писали:


MI0>>Здравствуйте, Аноним, Вы писали:

А>>>Используйте средства синхронизации, можно посмотреть здесь — http://msdn.microsoft.com/ru-ru/library/172d2hhw.aspx
MI0>>Синхронизация мне не поможет. Мне нужно чтобы обработчик исключения мог узнать о событии [Ctrl+C]. А получается так, что он
MI0>>сначала выполняется, а потом только в другом потоке выполняется обработчик события [Ctrl+C]. Можно создать событие, кот. будет дергать обработчик
MI0>>события [Ctrl+C] и подождать(где нить 500 мс) его в обработчике исключения, но это уже криво будет.

СМ>Я один раз сделал очень грубо. в Thread захватил контекст главного thread и выставил свой IP.

пока я буду в другом потоке выставлять IP, основной поток сделает то, чего мне не надо)
на крайний случай можно перечислить все потоки процесса и если их больше два, то не обрабатывать исключение в моем случае
СМ>Это чрезвычайно опасно, но обычно работает
это реально опасно
Re[5]: SetConsoleCtrlHandler и многопоточность
От: Сергей Мухин Россия  
Дата: 21.09.09 07:33
Оценка:
Здравствуйте, mityaj.it.0, Вы писали:


СМ>>Я один раз сделал очень грубо. в Thread захватил контекст главного thread и выставил свой IP.

MI0>пока я буду в другом потоке выставлять IP, основной поток сделает то, чего мне не надо)

suspendthread

MI0>на крайний случай можно перечислить все потоки процесса и если их больше два, то не обрабатывать исключение в моем случае

на это не стоит закладываться, т.к.
1. завтра ваша программа будет составной частью другой, со многими thread
2. некоторые WindowsAPI ф-ии запускают свои thread, и они не всегда останавливаются по завершению онной

СМ>>Это чрезвычайно опасно, но обычно работает

MI0>это реально опасно

не опасней IsBadReadPtr
---
С уважением,
Сергей Мухин
Re[6]: SetConsoleCtrlHandler и многопоточность
От: mityaj.it.0  
Дата: 21.09.09 07:54
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:

СМ>Здравствуйте, mityaj.it.0, Вы писали:



СМ>>>Я один раз сделал очень грубо. в Thread захватил контекст главного thread и выставил свой IP.

MI0>>пока я буду в другом потоке выставлять IP, основной поток сделает то, чего мне не надо)

СМ>suspendthread

не получится, потому что обработчик события [Ctrl+C] в другом потоке получит управление после обработки исключения в основном потоке(по крайней мере
это нельзя списывать)

MI0>>на крайний случай можно перечислить все потоки процесса и если их больше два, то не обрабатывать исключение в моем случае

СМ>на это не стоит закладываться, т.к.
СМ>1. завтра ваша программа будет составной частью другой, со многими thread
СМ>2. некоторые WindowsAPI ф-ии запускают свои thread, и они не всегда останавливаются по завершению онной
есть такое
Re[7]: SetConsoleCtrlHandler и многопоточность
От: Сергей Мухин Россия  
Дата: 21.09.09 07:59
Оценка:
Здравствуйте, mityaj.it.0, Вы писали:

СМ>>suspendthread

MI0>не получится, потому что обработчик события [Ctrl+C] в другом потоке получит управление после обработки исключения в основном потоке(по крайней мере
MI0>это нельзя списывать)

не понял. Мы сейчас работаем в обработчику Ctrl+C, и пытаемся передать другому thread (например главному) исключение. так?

так как мы получим управление _после_ обработки искл в главном? (т.е. получить то можем, но зачем?)
---
С уважением,
Сергей Мухин
Re[8]: SetConsoleCtrlHandler и многопоточность
От: mityaj.it.0  
Дата: 21.09.09 08:08
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:

СМ>Здравствуйте, mityaj.it.0, Вы писали:


СМ>>>suspendthread

MI0>>не получится, потому что обработчик события [Ctrl+C] в другом потоке получит управление после обработки исключения в основном потоке(по крайней мере
MI0>>это нельзя списывать)

СМ>не понял. Мы сейчас работаем в обработчику Ctrl+C, и пытаемся передать другому thread (например главному) исключение. так?


СМ>так как мы получим управление _после_ обработки искл в главном? (т.е. получить то можем, но зачем?)

Нет.
В главном потоке строка "std::cin >> itSum" ожидает от юзера ввода целого числа, если юзер передумает и захочет выйти,
то он нажмет [Ctrl+C]. В этом случае "std::cin >> itSum" сгенерит исключение(поскольку введено не значение типа int) и винда создаст поток, в кот. передаст управление моему обработчику "ConsoleHandler".
Мне не нужно обрабатывать исключение, поскольку это не ввод числа, а запрос на выход из программы. Вопрос в том, как основному потоку в обработчике исключения понять, что был запрос на выход, а не ввод неверного числа?
Re[9]: SetConsoleCtrlHandler и многопоточность
От: Сергей Мухин Россия  
Дата: 21.09.09 08:27
Оценка:
Здравствуйте, mityaj.it.0, Вы писали:


СМ>>так как мы получим управление _после_ обработки искл в главном? (т.е. получить то можем, но зачем?)

MI0>Нет.
MI0>В главном потоке строка "std::cin >> itSum" ожидает от юзера ввода целого числа, если юзер передумает и захочет выйти,
MI0>то он нажмет [Ctrl+C]. В этом случае "std::cin >> itSum" сгенерит исключение(поскольку введено не значение типа int) и винда создаст поток, в кот. передаст управление моему обработчику "ConsoleHandler".
MI0>Мне не нужно обрабатывать исключение, поскольку это не ввод числа, а запрос на выход из программы. Вопрос в том, как основному потоку в обработчике исключения понять, что был запрос на выход, а не ввод неверного числа?

понятно.
можно сделать так, что Ctrl+C не воспринимался потоком вообще?
не знаю что делать.
---
С уважением,
Сергей Мухин
Re[10]: SetConsoleCtrlHandler и многопоточность
От: Аноним  
Дата: 21.09.09 08:56
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:

СМ>>>гм. Это ОЧЕВИДНО когда написано eip = ...

СМ>>>И зачем. Все равно этот комментарий не раскрывает причин, почему опасно и тп.

А>>Я не до дословно имел ввиду : '//чрезвычайно опасно, но обычно работает', хотя даже это лучше чем ничего.

СМ>Вы дословно это написали, пишите что вы хотите сказать, что вы ДУМАЕТЕ понять из сообщение не возможно!

Я процитировал эту фразу в ответ на вопрос "Что тут пояснять?". Вроде как очевидно что это не является комментарием как таковым, но если не очевидно — это я сам виноват.

А>>Url/ссылка на книгу/статью... Хотя бы заострить на этом внимание. Пусть бы там было не 'Context->Eip = myHandler', а скажем 'service->reset()'. Да, возможно этот вызов раз в пятилетку приведет к плохому. Мне это так же ОЧЕВИДНО, как и вам про 'eip =', только дело не в этом — там любой код мог бы быть, про который можно сказать "опасно, но обычно работает"


СМ>ну вот я на той неделе потратил туеву хучу ввремени что бы найти ошибку в чужой программе. ошибка было (грубо говоря) a[i];

СМ>И помогли мне комментарии?

Возможно я опять неудачно выразился — давайте поделим <некторые> ошибки на две категории: программист уверен что участок кода работает верно, но сам при этом может ошибиться при его написании (т.е. надо 'i >= 0', а он написал 'i > 0') — то ли глаз замылился, то ли отвлекли и т.п., но он уверен что в коде все хорошо. В втором случае программист осознанно выбирает опасный способ реализации — и весьма вероятно, что в этом вероятны обстоятельства (релиз вчера, необходимость масштабного рефакторинга опять же, отсутствие полномочий для принятия решений, и тому подобное). Опасность выбранного случая заключается в том, что даже если он реализован без ошибок — этот код может выстрелить из-за внешних обстоятельств (как Вы сами сказали 'обычно работает').

ошибку в a[i] — я отношу к первой категории (для другого вывода не хватает данных)
'eip =...'/'service->reset()' — это вторая категория.

СМ>>>2. это плохая программа, если надо так делать, как все известно, комментарии ее на спасут

А>>Могут спасти... если все такие места будут помечены хотя бы чем-то вроде '// review' то как минимум их можно очень просто идентифицировать и потом предпринять какие-либо действия по исправлению.

СМ>если все места будут помечены — идеализм.

Стремиться к идеалу и выполнять действия, способствующие в его достижении — это плохо? Такие комментарии реально помогают. По Вашему получается — если программа содержит такой комментарий, то она плохая, комментарии ей не помогут... Такой комменатрий торчит как маяк и говорит "поправь меня". Как по мне, так польза налицо. Иначе можно просто _удалить_ (или не добавлять вообще) этот комментарий — от этого по Вашему программа становится хорошей, хотя "запашок" от такого удаления не исчезает.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.