在 mingw 和 wine 中杀死 fgets 线程
Kill fgets thread in mingw and wine
我有这个 program.cpp :
#include <stdio.h>
#include <windows.h>
DWORD WINAPI separateThread(LPVOID)
{ printf("thread waiting user input\n");
char str[128]; fgets(str, 128, stdin);
printf("fgets END ...");
}
int main()
{
printf("program start autokill after 5sec\n");
DWORD tid; HANDLE tha =CreateThread(0,0, separateThread, 0,0,&tid);
Sleep(5000);
// XXXXXXXX what to put here to Kill fgets-callin-thread ???????????
}
在 linux 中编译:
i686-w64-mingw32-gcc program.cpp
和运行它与:
wine a.exe
...而且我希望它在没有任何用户输入的情况下自行结束。但是总有err:ntdll:RtlpWaitForCriticalSection挡住了一切。
我应该在 XXXXX 位置放什么?
没有帮助的解决方案:
TerminateThread(tha, 0), ExitProcess(0), reopen(stdin), fclose(stdin) ... 通过 kbhit-getch 组合实现自己的 'my_gets' 函数是 xp、win7 和 win8 目标的良好解决方案,但是 kbhit在 WINE 中不起作用。
终止线程几乎从来都不安全。它可能会使事情处于不一致、损坏的状态。
例如,考虑一个正在内存分配中途的线程。线程锁定了用于同步堆访问的互斥量。如果突然终止,线程将不会释放锁。任何后续分配内存的尝试都将挂起。
一个可能的解决方案是终止整个进程(terminateprocess 函数)。这将导致所有线程被终止并且进程退出而不执行任何清理。这意味着例如 stdout 不会被刷新,注册的 atexit 处理程序不会 运行 以及任何 C++ 析构函数。但是 OS 级资源,如打开的文件和内存将被正确释放。
还有exitprocess来执行有序的进程关闭。它执行清理,但由于线程突然终止而导致全局状态损坏(考虑在清理期间调用 free() ,如果堆已损坏,它会挂起)。
旁注。使用 _beginthread instead of CreateThread 以便在新线程中正确初始化 c 运行time 库。
TerminateThread 只能确保在所有情况下都能杀死 fgets。
但我最后使用的最干净的解决方案是将输入发送到标准输入:
void sendEnterToStdin()
{ INPUT_RECORD ir[2];
for (int i=0; i<2; i++)
{ KEY_EVENT_RECORD *kev =&ir[i].Event.KeyEvent;
ir[i].EventType =KEY_EVENT;
kev->bKeyDown = i==0; //<-true, than false
kev->dwControlKeyState = 0;
kev->wRepeatCount = 1;
kev->uChar.UnicodeChar = VK_RETURN;
kev->wVirtualKeyCode = VK_RETURN;
kev->wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC);
}
DWORD dw; WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), ir, 2, &dw);
}
... 并使其适用于 WINE :
using ' $ wineconsole --backend=curses a.exe ' instead of ' $ wine a.exe '
我有这个 program.cpp :
#include <stdio.h>
#include <windows.h>
DWORD WINAPI separateThread(LPVOID)
{ printf("thread waiting user input\n");
char str[128]; fgets(str, 128, stdin);
printf("fgets END ...");
}
int main()
{
printf("program start autokill after 5sec\n");
DWORD tid; HANDLE tha =CreateThread(0,0, separateThread, 0,0,&tid);
Sleep(5000);
// XXXXXXXX what to put here to Kill fgets-callin-thread ???????????
}
在 linux 中编译:
i686-w64-mingw32-gcc program.cpp
和运行它与:
wine a.exe
...而且我希望它在没有任何用户输入的情况下自行结束。但是总有err:ntdll:RtlpWaitForCriticalSection挡住了一切。
我应该在 XXXXX 位置放什么?
没有帮助的解决方案: TerminateThread(tha, 0), ExitProcess(0), reopen(stdin), fclose(stdin) ... 通过 kbhit-getch 组合实现自己的 'my_gets' 函数是 xp、win7 和 win8 目标的良好解决方案,但是 kbhit在 WINE 中不起作用。
终止线程几乎从来都不安全。它可能会使事情处于不一致、损坏的状态。
例如,考虑一个正在内存分配中途的线程。线程锁定了用于同步堆访问的互斥量。如果突然终止,线程将不会释放锁。任何后续分配内存的尝试都将挂起。
一个可能的解决方案是终止整个进程(terminateprocess 函数)。这将导致所有线程被终止并且进程退出而不执行任何清理。这意味着例如 stdout 不会被刷新,注册的 atexit 处理程序不会 运行 以及任何 C++ 析构函数。但是 OS 级资源,如打开的文件和内存将被正确释放。
还有exitprocess来执行有序的进程关闭。它执行清理,但由于线程突然终止而导致全局状态损坏(考虑在清理期间调用 free() ,如果堆已损坏,它会挂起)。
旁注。使用 _beginthread instead of CreateThread 以便在新线程中正确初始化 c 运行time 库。
TerminateThread 只能确保在所有情况下都能杀死 fgets。
但我最后使用的最干净的解决方案是将输入发送到标准输入:
void sendEnterToStdin()
{ INPUT_RECORD ir[2];
for (int i=0; i<2; i++)
{ KEY_EVENT_RECORD *kev =&ir[i].Event.KeyEvent;
ir[i].EventType =KEY_EVENT;
kev->bKeyDown = i==0; //<-true, than false
kev->dwControlKeyState = 0;
kev->wRepeatCount = 1;
kev->uChar.UnicodeChar = VK_RETURN;
kev->wVirtualKeyCode = VK_RETURN;
kev->wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC);
}
DWORD dw; WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), ir, 2, &dw);
}
... 并使其适用于 WINE :
using ' $ wineconsole --backend=curses a.exe ' instead of ' $ wine a.exe '