Related
In Win32 C++, How to WaitForSingleObject and Detect Ctrl-C at the same time?
I tried the following console application by compiling it in the Code::Blocks C++ compiler for windows.
Then, I tried pressing Control-C many times while running... it basically doesn't call the control-c handler while the main thread is in "WaitForSingleObject".
Is there a way to fix this?
Eventually, I want my Control-C handler to kill the secondary thread using TerminateThread and return control to mainthread breaking WaitForSingleObject... But, because of the wait the second thread is written i can't change any of the code...
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <atomic>
using namespace std;
BOOL WINAPI fun1(DWORD id);
DWORD WINAPI fun2(void*);
atomic<DWORD> threadid {0};
int main()
{
DWORD threadid1;
cout << "Hello world!" << endl;
SetConsoleCtrlHandler(fun1, TRUE);
HANDLE H1 = CreateThread(NULL, 0, fun2, 0, 0, &threadid1);
threadid = threadid1;
WaitForSingleObject(H1, INFINITE);
return 0;
}
BOOL WINAPI fun1(DWORD id)
{
Beep(750, 300);
printf("CtrlHandler:(%ld)\n", id);
if (threadid != 0) {
HANDLE H2 = OpenThread(THREAD_TERMINATE, FALSE, threadid);
if (H2) {
//TerminateThread(H2, 0);
//threadid = 0;
CloseHandle(H2);
}
}
return TRUE;
}
DWORD WINAPI fun2(void*)
{
// This thread will eventually do some work...
// and I don't want to rewrite this code...
// to check for a flag from another thread...
int count = 0;
while(1) {
printf("count: %d\n", count);
Sleep(1000);
}
return 0;
}
A SetConsoleCtrlHandler() handler gets run by the OS in its own thread. This is stated as much in the documentation:
https://learn.microsoft.com/en-us/windows/console/handlerroutine
An application-defined function used with the SetConsoleCtrlHandler function. A console process uses this function to handle control signals received by the process. When the signal is received, the system creates a new thread in the process to execute the function.
You need to have that signal thread notify your worker thread to terminate itself, you can't (safely) just terminate the thread directly (ie, DO NOT use TerminateThread()).
Try this:
#include <windows.h>
#include <cstdio>
#include <iostream>
#include <atomic>
using namespace std;
BOOL WINAPI fun1(DWORD);
DWORD WINAPI fun2(void*);
atomic<bool> exitThread {false};
int main()
{
cout << "Hello world!" << endl;
SetConsoleCtrlHandler(fun1, TRUE);
HANDLE H1 = CreateThread(NULL, 0, fun2, 0, 0, NULL);
if (H1)
{
WaitForSingleObject(H1, INFINITE);
CloseHandle(H1);
}
return 0;
}
BOOL WINAPI fun1(DWORD id)
{
Beep(750, 300);
printf("CtrlHandler:(%lu)\n", id);
exitThread = true;
return TRUE;
}
DWORD WINAPI fun2(void*)
{
// This thread will eventually do some work...
int count = 0;
while (!static_cast<bool>(exitThread)) {
printf("count: %d\n", count++);
Sleep(1000);
}
return 0;
}
However, do note that creating a thread just to wait on it is a waste of a thread. You may as well just do your work in main() directly instead, eg:
#include <windows.h>
#include <cstdio>
#include <iostream>
#include <atomic>
using namespace std;
BOOL WINAPI fun1(DWORD);
atomic<bool> exitApp {false};
int main()
{
cout << "Hello world!" << endl;
SetConsoleCtrlHandler(fun1, TRUE);
// This will eventually do some work...
int count = 0;
while (!static_cast<bool>(exitApp)) {
printf("count: %d\n", count++);
Sleep(1000);
}
return 0;
}
BOOL WINAPI fun1(DWORD id)
{
Beep(750, 300);
printf("CtrlHandler:(%lu)\n", id);
exitApp = true;
return TRUE;
}
I cleaned up your code slightly and it seems like the Ctrl+C handler is running when expected (even though it doesn't do anything particularly useful). When I type Ctrl+C, I see that fun1 can run multiple times while the main thread is running WaitForSingleObject.
Your original code for fun1 was beeping before printing, and it wasn't flushing the stdout buffer, so maybe you thought the code wasn't actually running or that it was getting delayed.
Note that I am just answering questions you asked about detecting Ctrl+C while waiting for an object; I'm not attempting to help you do anything useful in your Ctrl+C handler.
Here is the cleaned-up version of your code that I used for testing:
#include <windows.h>
#include <stdio.h>
#include <atomic>
std::atomic<DWORD> threadid {0};
BOOL WINAPI fun1(DWORD id) {
printf("fun1: %ld\n", id);
fflush(stdout);
Beep(750, 100);
// This doesn't do anything useful; can be removed.
if (threadid != 0) {
HANDLE H2 = OpenThread(THREAD_TERMINATE, FALSE, threadid);
if (H2) { CloseHandle(H2); }
}
return 1;
}
DWORD WINAPI fun2(void *) {
unsigned int count = 0;
while(1) {
count++;
printf("count: %d\n", count);
fflush(stdout);
Sleep(4000);
}
return 0;
}
int main() {
printf("Hello world!\n");
fflush(stdout);
SetConsoleCtrlHandler(fun1, TRUE);
DWORD threadid1;
HANDLE H1 = CreateThread(NULL, 0, fun2, 0, 0, &threadid1);
threadid = threadid1;
printf("Waiting for single oblect.\n");
fflush(stdout);
WaitForSingleObject(H1, INFINITE);
printf("Done waiting for single oblect.\n");
fflush(stdout);
return 0;
}
Example output:
Hello world!
Waiting for single oblect.
count: 1
count: 2
fun1: 0
fun1: 0
fun1: 0
fun1: 0
fun1: 0
fun1: 0
fun1: 0
fun1: 0
fun1: 0
count: 3
count: 4
I compiled the code in MSYS2, targeting 64-bit Windows, with this command:
g++ -std=gnu++20 -Wall -Wextra test.cpp
When I execute system in a thread, nothing happens. Is there a solution?
#include <iostream>
#include <Windows.h>
using namespace std;
void runffplay()
{
const char* _cmd = "ffplay -fs -loop 0 \"D:\\dynamic wallpaper\\1.mp4\"";
system(_cmd);
}
CloseHandle(CreateThread(0, 0, (PTHREAD_START_ROUTINE)runffplay, 0, 0, 0));
Your runffplay() function has the wrong signature, so you are going to end up corrupting the thread's call stack. Read the CreateThread() and ThreadProc documentations.
Also, you are not doing any error handling.
Try something more like this instead:
#include <iostream>
#include <cstdlib>
#include <Windows.h>
DWORD WINAPI runffplay(LPVOID)
{
// instead of system(), consider using exec..(), or CreateProcess() directly...
const char* _cmd = "ffplay -fs -loop 0 \"D:\\dynamic wallpaper\\1.mp4\"";
int ret = std::system(_cmd);
std::cout << "system() returned " << ret << std::endl;
return 0;
}
HANDLE hThread = CreateThread(NULL, 0, runffplay, NULL, 0, NULL);
if (!hThread) {
DWORD err = GetLastError();
std::cerr << "CreateThread() failed with error " << err << std::endl;
}
else {
...
CloseHandle(hThread);
}
Otherwise, use std::thread instead of CreateThread() directly:
#include <iostream>
#include <thread>
#include <cstdlib>
void runffplay()
{
// instead of system(), consider using exec..(), or CreateProcess() directly...
const char* _cmd = "ffplay -fs -loop 0 \"D:\\dynamic wallpaper\\1.mp4\"";
int ret = std::system(_cmd);
std::cout << "system() returned " << ret << std::endl;
}
std::thread thrd;
try {
thrd = std::thread(runffplay);
}
catch (const std::system_error &e) {
std::cerr << "thread failed with error " << e << std::endl;
}
...
if (thrd.joinable()) {
thrd.join();
}
Use CreateProcess to get the expected result
#include <iostream>
#include <Windows.h>
using namespace std;
HWND ffplayw = 0;
void SetWallpaper()
{
while (ffplayw == 0)
{
ffplayw = FindWindowW(L"SDL_app", 0);
Sleep(10);
}
}
int main()
{
STARTUPINFO info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
if (CreateProcess(L"D:\\my-tools\\ffmpeg\\bin\\ffplay.exe",
(LPWSTR)L" -fs -loop 0 \"D:\\dynamic wallpaper\\1.mp4\"",
0, 0, 0, 0, 0, 0, &info, &processInfo))
{
// WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
Sleep(500);
SetWallpaper();
}
return 0;
}
this is okay too:
CreateProcess(
L"C:\\Windows\\System32\\cmd.exe",
(LPWSTR)L" /c ffplay -loop 0 \"D:\\dynamic wallpaper\\1.mp4\"",
0, 0, 0, 0, 0, 0, &info, &processInfo)
I have a question regarding Win32 API process treatment.
I have two processes. Process 1, before starting, must run process 2, which waits for the same resource as process 1. It is a .txt file with some integer values. It means that Process1 should be started FIRST and run Process2. The Process1 MUST be completed after Process2.
It should work as followig:
1.Process1 is created.
2.Process 1 is blocked.
3.Process 2 is created and excecuted.
4.Process 1 is unlocked and executed.
5.Process 2 ends.
6.Process 1 ends.
I searched here for a question similar to mine, I've found only the link below, where a SpinLock class is presented:
C++11 Implementation of Spinlock using <atomic>
The issue is to implement it correctly, I've deleted my incorrect implementations of SpinLock methods from main() function.
It was almost impossible to find any example of using this method in practice, hence I am asking this question to have a look on it:
#include <iostream>
#include <Windows.h>
#include <string>
#include <tchar.h>
#include <cstdlib>
#include <pthread.h>
#include <atomic>
using namespace std;
class SpinLock {
atomic_flag locked = ATOMIC_FLAG_INIT ;
public:
void lock() {
while (locked.test_and_set(memory_order_acquire)) { ; }
}
void unlock() {
locked.clear(memory_order_release);
}
};
int main( int argc, TCHAR *argv[] )
{
//process 1 generates N random values between 1 and 100,then saves it to txt file i argv[1] stores quanity of values, which will be saved to file
STARTUPINFO si = {};
si.cb = sizeof si;
SpinLock SpinLockVar;
PROCESS_INFORMATION pi = {};
const TCHAR* target1 = _T("C:\\USERS\\Admin\\Documents\\File1.exe"); //process 1
const TCHAR* target2 = _T("C:\\USERS\\Admin\\Documents\\File2.exe");
//Process 1 , before starting generating values and saving them to file, runs Process2,which is awaiting for access to txt file (SPINLOCK ).
//Process 1 is terminating after finishing Process 2
if ( !CreateProcess(target1,GetCommandLine(), 0, FALSE, 0, 0, 0, 0, &si, &pi) )
{
cerr << "CreateProcess failed (" << GetLastError() << ").\n";
}
else
{
WaitForSingleObject(pi.hProcess, INFINITE);
if ( PostThreadMessage(pi.dwThreadId, WM_QUIT, 0, 0) ) // Good
cout << "Request to terminate process has been sent!";
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
if ( !CreateProcess(target2,0, 0, FALSE, 0, 0, 0, 0, &si, &pi) )
{
cerr << "CreateProcess failed (" << GetLastError() << ").\n";
}
else
{
WaitForSingleObject(pi.hProcess, INFINITE);
/*
if ( TerminateProcess(pi.hProcess, 0) ) // Evil
cout << "Process terminated!";
*/
if ( PostThreadMessage(pi.dwThreadId, WM_QUIT, 0, 0) ) // Good
cout << "Request to terminate process has been sent!";
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
cin.sync();
cin.ignore();
return 0;
}
UPDATE
I have used mutex function for now, and it works partially - it has a mutex "spinlock" mechanism, although it sometimes displaying very strange. I have randomly the result which I expect and which is generating randomly after running my program - the first line in cmd is from thread which runs process2, the second line is result of process1
Please check my code :
#include <windows.h>
#include <stdio.h>
#include <pthread.h>
#include <tchar.h>
#include <mutex>
#include <iostream>
HANDLE hMutex;
DWORD ThreadProc1(LPVOID* arg)
{
const TCHAR* target = _T("C:\\USERS\\Admin\\Documents\\File2.exe");
PROCESS_INFORMATION pInfo;
STARTUPINFO sInfo = { sizeof(pInfo) };
BOOL res = CreateProcess(target, 0, 0, FALSE, 0, 0, 0, 0, &sInfo, &pInfo); //process2
if (!res) return 1;
WaitForSingleObject(pInfo.hThread, INFINITE);
CloseHandle(pInfo.hThread);
CloseHandle(pInfo.hProcess);
return TRUE;
}
int main(void)
{
PROCESS_INFORMATION pInfo;
STARTUPINFO sInfo = { sizeof(pInfo) };
const TCHAR* target = _T("C:\\USERS\\Admin\\Documents\\File1.exe");
HANDLE hThreads;
DWORD threadID1;
hMutex=CreateMutex(NULL, FALSE, NULL); //create mutex(resources=1)
WaitForSingleObject(hMutex, INFINITE); //process2 call WaitForSingleObject(hmutex) first to get mutex
hThreads=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc1, &hMutex, 0, &threadID1);
WaitForSingleObject(hMutex,INFINITE);//process1 call WaitForSingleObject(hmutex) and block
BOOL res = CreateProcess(target, GetCommandLine(), 0, FALSE, 0, 0, 0, 0, &sInfo, &pInfo);//process1
if (!res) return 1;
ReleaseMutex(hMutex);// process2 do file operations, and then release mutex
WaitForSingleObject(hMutex,INFINITE);// process1 WaitForSingleObject(hmutex) unblock(resources -1),
ReleaseMutex(hMutex); // then release mutex(resources +1)
CloseHandle(hMutex);
WaitForSingleObject(hThreads,INFINITE);
CloseHandle(hThreads); //process 1 closing thread after process 2 ends
CloseHandle(pInfo.hProcess);
CloseHandle(pInfo.hThread);
return 0;
}
First, I think you don't need to use mutex or Spinlock. You could create process1 with CREATE_SUSPENDED, create process2, wait for process2 to exit, then call ResumeThread(pi1.hThread) although there may be differences in step 4 and 5.
#include <windows.h>
#include <string>
#include <tchar.h>
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, TCHAR* argv[])
{
STARTUPINFO si1 = { 0 }, si2 = { 0 };
si1.cb = sizeof si1;
si2.cb = sizeof si2;
PROCESS_INFORMATION pi1 = { 0 }, pi2 = { 0 };
const TCHAR* target1 = _T("C:\\Users\\drakew\\source\\repos\\Project4\\Debug\\Project4.exe");
const TCHAR* target2 = _T("C:\\Users\\drakew\\source\\repos\\Project6\\Debug\\Project6.exe");
if (!CreateProcess(target1, 0, 0, FALSE, 0, CREATE_SUSPENDED, 0, 0, &si1, &pi1))
{
cerr << "CreateProcess failed (" << GetLastError() << ").\n";
}
else
{
printf("Process1 is created ...\n");
printf("Process1 is blocked ...\n");
if (!CreateProcess(target2, 0, 0, FALSE, 0, 0, 0, 0, &si2, &pi2))//Process 2 is created and excecuted ...
{
cerr << "CreateProcess failed (" << GetLastError() << ").\n";
}
else
{
WaitForSingleObject(pi2.hProcess, INFINITE);
printf("Process 2 ends ...\n");
CloseHandle(pi2.hProcess);
CloseHandle(pi2.hThread);
}
ResumeThread(pi1.hThread); //Process 1 is unlocked and executed ...
WaitForSingleObject(pi1.hProcess, INFINITE);
printf("Process 1 ends ...\n");
CloseHandle(pi1.hProcess);
CloseHandle(pi1.hThread);
}
cin.sync();
cin.ignore();
return 0;
}
Then, If you want to block at the specific location of process1, then you have to modify process1 and process2 to keep synchronization.
I use event to implement lock.
Process1:
#include <Windows.h>
#include <iostream>
using namespace std;
int main()
{
HANDLE hEvent1 = OpenEvent(EVENT_MODIFY_STATE| SYNCHRONIZE, FALSE, L"Global\\MyEvent1");
HANDLE hEvent2 = OpenEvent(EVENT_MODIFY_STATE| SYNCHRONIZE, FALSE, L"Global\\MyEvent2");
printf("process1: step1 ...\n");
SetEvent(hEvent1);
printf("process1: step2 ...\n");
DWORD dwWaitResult = WaitForSingleObject(hEvent2, INFINITE);
switch (dwWaitResult)
{
case WAIT_OBJECT_0:
printf("process1: step4 ...\n");
break;
default:
return FALSE;
}
CloseHandle(hEvent1);
CloseHandle(hEvent2);
}
Process2:
#include <Windows.h>
#include <iostream>
using namespace std;
int main()
{
HANDLE hEvent1 = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, L"Global\\MyEvent1");
HANDLE hEvent2 = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, L"Global\\MyEvent2");
DWORD dwWaitResult = WaitForSingleObject(hEvent1, INFINITE);
switch (dwWaitResult)
{
case WAIT_OBJECT_0:
printf("process2: step3 ...\n");
SetEvent(hEvent2);
break;
default:
return FALSE;
}
CloseHandle(hEvent1);
CloseHandle(hEvent2);
return 1;
}
Main Process:
#include <windows.h>
#include <string>
#include <tchar.h>
#include <cstdlib>
#include <mutex>
#include <iostream>
using namespace std;
int main(int argc, TCHAR* argv[])
{
STARTUPINFO si1 = { 0 }, si2 = { 0 };
si1.cb = sizeof si1;
si2.cb = sizeof si2;
PROCESS_INFORMATION pi1 = { 0 }, pi2 = { 0 };
mutex mtx;
HANDLE hEvent1 = CreateEvent(NULL, FALSE, FALSE, L"Global\\MyEvent1");
HANDLE hEvent2 = CreateEvent(NULL, FALSE, FALSE, L"Global\\MyEvent2");
const TCHAR* target1 = _T("C:\\path\\process1.exe");
const TCHAR* target2 = _T("C:\\path\\process2.exe");
if (!CreateProcess(target1, 0, 0, FALSE, 0, 0, 0, 0, &si1, &pi1))
{
cerr << "CreateProcess failed (" << GetLastError() << ").\n";
}
else
{
if (!CreateProcess(target2, 0, 0, FALSE, 0, 0, 0, 0, &si2, &pi2))
{
cerr << "CreateProcess failed (" << GetLastError() << ").\n";
}
else
{
WaitForSingleObject(pi2.hProcess, INFINITE);
printf("process2: step5 ...\n");
CloseHandle(pi2.hProcess);
CloseHandle(pi2.hThread);
}
WaitForSingleObject(pi1.hProcess, INFINITE);
printf("process1: step6 ...\n");
CloseHandle(pi1.hProcess);
CloseHandle(pi1.hThread);
}
CloseHandle(hEvent1);
CloseHandle(hEvent2);
cin.sync();
cin.ignore();
return 0;
}
Result:
I'm investigating the use of PThread.
The main process opens the camera and gets a matrix. Then calls the thread that running job in robot and I want it to be parallel. Basically it works and runs. But still feel unprofessional- because of the bool.
In the code below, this is an example (with fprintf).
I'd love to know how I can fix it without harm parallelism.
In the next code I do not show the call to the robot or camera opening.
There is a feeling that a mutex is needed.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <opencv2/opencv.hpp>
#include <unistd.h> /// for sleep
bool inThread = false;
void *print_message_function( void *ptr );
int main()
{
char mkey = 0;
pthread_t thread1;
char *message1 = "Thread 1";
int iret1;
cv::Mat bgr_image = imread("image.bmp",cv::IMREAD_COLOR);
while(mkey!=27){
if(!inThread){
inThread = true;
iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);
}
printf("In Main");
imshow("mat", bgr_image);
mkey = cv:: waitKey(5);
}
return 0;
}
void *print_message_function( void *ptr )
{
char *message;
message = (char *) ptr;
printf("%s \n", message);
sleep(2);
inThread = false;
pthread_exit(NULL);
}
The code works great and does not fall, but it seems unprofessional. Is there a chance that when you update the flag, it will check what is in the flag and fall?
inThread is concurrently read/written so its access shall be protected.
Using a mutex this can for example be done like follows.
Define a global mutex and initialise it:
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
Include errno to be able to do convenient error checking/logging for the pthread_*() calls:
#include <errno.h>
Change this
if(!inThread){
inThread = true;
iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);
}
to become
errno = pthread_mutex_lock(&m);
if (errno) {
perror("pthread_mutex_lock() failed");
exit(EXIT_FAILURE);
}
if (!inThread) {
inThread = true;
errno = pthread_mutex_unlock(&m);
if (errno) {
perror("pthread_mutex_unlock() failed");
exit(EXIT_FAILURE);
}
...
}
else {
errno = pthread_mutex_unlock(&m);
if (errno) {
perror("pthread_mutex_unlock() failed");
exit(EXIT_FAILURE);
}
}
And change this
inThread = false;
to become
errno = pthread_mutex_lock(&m);
if (errno) {
perror("pthread_mutex_lock() failed");
exit(EXIT_FAILURE);
}
inThread = false;
errno = pthread_mutex_unlock(&m);
if (errno) {
perror("pthread_mutex_unlock() failed");
exit(EXIT_FAILURE);
}
In windows 10, if i create a process to open calc.exe first its trigger calc.exe and exit that process after that it opens calculator.exe. How can i get actual process id that shows in task manager.
i am using following code to create the process and display process id
if(!CreateProcess(("C:\\WINDOWS\\system32\\calc.exe"),
NULL,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&startup_info,
&pi) )
{
args.GetReturnValue().Set(Nan::New(response).ToLocalChecked());
}
else
{
int dwPid = GetProcessId(pi.hProcess);
int v = dwPid->Int32Value();
args.GetReturnValue().Set(dwPid);
}
#include <iostream>
#include <vector>
#include <cstring>
#include <windows.h>
#include <tlhelp32.h>
using std::vector;
using std::cout;
using std::endl;
vector<DWORD> pids_from_ppid(DWORD ppid) {
vector<DWORD> pids;
HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe = { 0 };
pe.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hp, &pe)) {
do {
if (pe.th32ParentProcessID == ppid) {
pids.push_back(pe.th32ProcessID);
}
} while (Process32Next(hp, &pe));
}
CloseHandle(hp);
return pids;
}
int main(int argc,char *argv[]) {
if (arc >= 2) {
DWORD ppid = (DWORD)strtoul(argv[1], nullptr, 10);
vector<DWORD> pidVec = pids_from_ppid(ppid);
for (int i = 0; i < pidVec.size(); i++) {
cout << pidVec[i] << endl;
}
}
return 0;
}