Create, Suspend and Resume Windows Threads

I'm looking for a more concise example of using windows threads, even with a main loop just running in a console app where the thread function increments a variable forever and perhaps some delay, with a create suspend and resume control (getchar?) on the main loop.

So far the tutorials I found in the web are either really basic and simple or so complex.. I'm using C.

Last edited on
Hello. This is a simple example in order to create a thread which display each second a brief message - its ID. During this process press some keyboard keys to get their ASCII values. The thread works as a background process. I hope that it helps you ++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>     // for the console
#include <thread>       // for the thread
#include <windows.h>    // for the keyboard events
#include <conio.h>      // for _getch()

class new_thread {

public:
    void operator()(const int x)
    {
        for (int i = 0; i < x; i++)
        {
            std::cout << "Thread ID : " << std::this_thread::get_id() << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }

        std::cout << "End Of Thread" << std::endl;
    }
};

int main()
{   // only ten seconds
    std::thread myThread(new_thread(), 10);
    char key;
    int ascii_value;

    while (1)
    {
        key = _getch();
        ascii_value = key;
        // escape key
        if (ascii_value == 27)
        {
            std::cout << "Goodbye!" << std::endl;
            break;
        }

        std::cout << "Key pressed -> " << key << " ASCII Value = " << ascii_value << std::endl;
    }

    myThread.join();

    return 0;
}
Last edited on
Usually I prefer to use Detach() instead of Join().
It seems to me more stable according to all other processes ++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>     // for the console
#include <thread>       // for the thread
#include <windows.h>    // for the keyboard events
#include <conio.h>      // for _getch()

class new_thread {

public:
    void operator()(const int x)
    {
        for (int i = 0; i < x; i++)
        {
            std::cout << "Thread ID : " << std::this_thread::get_id() << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }

        std::cout << "End Of Thread" << std::endl;
    }
};

int main()
{
    std::thread myThread(new_thread(), 10);
    myThread.detach();

    char key;
    int ascii_value;

    while (1)
    {
        key = _getch();
        ascii_value = key;

        if (ascii_value == 27)
        {
            std::cout << "Goodbye!" << std::endl;
            break;
        }

        std::cout << "Key pressed -> " << key << " ASCII Value = " << ascii_value << "\n";
    }

    return 0;
}
Last edited on
To Pause and Resume your thread, you can simply use SuspendThread() and ResumeThread(). If you want to kill it before the end, you can use an Atomic Boolean which can be read by every process ++

https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-suspendthread
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-resumethread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>     // for the console
#include <thread>       // for the thread
#include <windows.h>    // for the keyboard events
#include <conio.h>      // for _getch()
#include <atomic>       // for atomic boolean

std::atomic<bool> exit_thread_flag{ false };

class new_thread {

public:
    void operator()(const int x)
    {
        for (int i = 0; i < x; i++)
        {   // it's time to quit
            if (exit_thread_flag) break;

            std::cout << "Thread ID : " << std::this_thread::get_id() << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }

        std::cout << "End Of Thread" << std::endl;
    }
};

int main()
{
    std::thread myThread(new_thread(), 10);

    char key{};
    int ascii_value{};

    while(1)
    {
        key = _getch();
        ascii_value = key;
        // (p) for thread pause
        if (ascii_value == 112)
            SuspendThread(myThread.native_handle());
        // (r) to resume thread
        if (ascii_value == 114)
            ResumeThread(myThread.native_handle());
        // (k) to kill the thread
        if (ascii_value == 107)
            exit_thread_flag = true;

        if (ascii_value == 27)
        {
            std::cout << "Goodbye!" << std::endl;
            break;
        }

        std::cout << "Key pressed -> " << key << " ASCII Value = " << ascii_value << "\n";
    }

    myThread.join();

    return 0;
}
Last edited on
From OP post #1 - I'm using C.
lol :)
Sorry. I have a bad tendency to read diagonally...
I guess that there is no way to convert it easily :/
Last edited on
Since this was asked in the Windows forum, here is the "native" Windows way of doing it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <Windows.h>
#include <process.h>
#include <stdio.h>

static unsigned _stdcall thread_main(void* arg)
{
    fprintf(stderr, "Hello from thread! (ThreadID: %u)\n", GetCurrentThreadId());
    Sleep(5000); // <-- simulate some work the thread might be doing
    return 42;
}

int main()
{
    // start thread
    // note: we should use _beginthreadex() instead of calling CreateThread() directly!
    fputs("Creating thread...\n", stderr);
    HANDLE hThread = (HANDLE) _beginthreadex(NULL, 0, thread_main, NULL, CREATE_SUSPENDED, NULL);
    if (!hThread)
    {
        fputs("Failed to create thread!\n", stderr);
        return 1;
    }

    fputs("Thread created sucessfully.\n", stderr);

    // wait some time
    fputs("Sleeping...\n", stderr);
    Sleep(5000);
    fputs("Wake up!\n", stderr);

    // resume thread
    fputs("Resuming thread...\n", stderr);
    if (ResumeThread(hThread) == ((DWORD)(-1)))
    {
        fputs("Failed to resume thread!\n", stderr);
        return 1;
    }

    fputs("Thread resumed.\n", stderr);
    Sleep(100);

    // wait for thread to terminate
    fputs("Waiting for thread...\n", stderr);
    WaitForSingleObject(hThread, INFINITE);

    // get thread result (return value)
    DWORD result;
    if (!GetExitCodeThread(hThread, &result))
    {
        fputs("Failed to get exit code!\n", stderr);
        return 1;
    }

    fprintf(stderr, "Thread has terminated (result: %u).\n", result);

    // clean-up!
    CloseHandle(hThread);
}

Creating thread...
Thread created sucessfully.
Sleeping...
Wake up!
Resuming thread...
Thread resumed.
Hello from thread! (ThreadID: 16472)
Waiting for thread...
Thread has terminated (result: 42).

________

However, if you want to write portable C code, I'd recommend using the pthreads (POSIX Threads) API:
https://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread.h.html

It is also available on the Windows platform thanks to pthreads4w (formerly pthread-w32) project:
https://sourceforge.net/projects/pthreads4w/files/
Last edited on
And if using C++ there is C++11 stdlib's <thread> library that has std::thread.
https://en.cppreference.com/w/cpp/thread/thread

C++20 added std::jthread:
https://en.cppreference.com/w/cpp/thread/jthread

Both are part of the C++ concurrency support library:
https://en.cppreference.com/w/cpp/thread

The C stdlib has optionally provided thread support as well since C11:
https://en.cppreference.com/w/c/thread
But if you're writing Windows code, why not use what Windows provides? Together with Windows events etc, it's quite powerful.

https://docs.microsoft.com/en-us/windows/win32/procthread/processes-and-threads
https://docs.microsoft.com/en-us/windows/win32/sync/synchronization

and expand all in the left panes.
Last edited on
Thanks guys for the various solutions.

but yes, I am particularly looking for C and not C++.

@kigar

Thanks, but your example is the same as the tutorials that I already read and not really showing a variable increment.

where the thread function increments a variable forever and perhaps some delay, with a create suspend and resume control (getchar?) on the main loop.


again as per my post, it would be nice to show it started and then suspended through key press to see the current value on key press.

The GetExitCodeThread was new for me though.

I did replace the Sleep() part with an variable increment forever loop, but the program did loop forever where I am stuck.

1
2
3
4
5
6
7
8
9
10
11
12
int x, running; //globals

static unsigned _stdcall thread_main(void *arg)
{
	fprintf(stderr, "Hello from thread! (ThreadID: %u)\n", GetCurrentThreadId());
	while (running) // <-- simulate some work the thread might be doing
	{
		x++;
	}
	return x;
}


@Geckoo

The last one was close, but in C++
Last edited on
If you want to safely (atomically) increment a variable that is access by concurrent threads, use InterlockedIncrement().

1
2
3
4
5
6
7
8
9
10
11
12
volatile BOOL g_running = TRUE;
volatile LONG g_counter = 0;

static unsigned _stdcall thread_main(void *arg)
{
	while (g_running)
	{
		InterlockedIncrement(&g_counter);
		Sleep(125); // <-- add some small delay
	}
	return 0;
}


You can suspend/resume the "worker" thread at any time, by calling SuspendThread() or ResumeThread() from the "main" thread.

Also, you can simply set the global g_running flag to FALSE in order to cause the thread to exit. Of course, the thread must be running (resumed), so that it actually can test the g_running flag and then exit; a suspended thread will never exit by itself ;-)

A thread can also be terminated via TerminateThread(), but that is discouraged, as it can result in deadlock and/or resource leak!
Last edited on
As another take on this using events, consider something like (as c):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#define WIN32_LEAN_AND_MEAN

#include <Windows.h>
#include <stdio.h>
#include <conio.h>
#include <process.h>

const char* const ev1 = "thterm";
const char* const ev2 = "thstrt";

unsigned __stdcall myThread(LPVOID) {
	const HANDLE hterm = OpenEvent(EVENT_ALL_ACCESS, FALSE, ev1);
	const HANDLE hstart = OpenEvent(EVENT_ALL_ACCESS, FALSE, ev2);

	if (hterm == 0 || hstart == 0) {
		puts("Cannot open events");
		return 1;
	}

	SetEvent(hstart);
	SuspendThread(GetCurrentThread());

	const char* const str = "abcdefghijklmnopqrstuvwxyz";

	for (unsigned i = 0; WaitForSingleObject(hterm, 1000) == WAIT_TIMEOUT; )
		putchar(str[i++ % 26]);

	return 0;
}

int main() {
	const HANDLE hterm = CreateEvent(NULL, TRUE, FALSE, ev1);
	const HANDLE hstart = CreateEvent(NULL, TRUE, FALSE, ev2);

	const HANDLE hthrd = (HANDLE)_beginthreadex(NULL, NULL, &myThread, NULL, 0, NULL);

	if (hthrd == 0) {
		puts("Failed to start thread");
		return 1;
	}

	DWORD ecode = 99;

	if (WaitForSingleObject(hstart, 1000) == WAIT_OBJECT_0) {
		puts("Thread started ok - suspended\n(s)uspend, (r)resume, (t)terminate: ");

		while (WaitForSingleObject(hthrd, 0)) {
			if (_kbhit())
				switch (_getch()) {
					case 's':
						SuspendThread(hthrd);
						break;

					case 'r':
						ResumeThread(hthrd);
						break;

					case 't':
						ResumeThread(hthrd);
						SetEvent(hterm);
						break;

					default:
						putchar('\a');
						break;
				}
		}
	} else
		puts("Thread not running!");

	GetExitCodeThread(hthrd, &ecode);

	if (ecode)
		printf("Issue with thread - %u\n", ecode);
	else
		puts("\nThread terminated OK");

	return ecode;
}


If you need to 'share' a variable across multiple threads, then use the interlock set of functions. See:
https://docs.microsoft.com/en-us/windows/win32/sync/interlocked-variable-access
https://docs.microsoft.com/en-us/windows/win32/sync/synchronization-functions

There are also the critical section access functions which limits the specified code to only one access at a time.
Last edited on
For intra process synchronization you don't need a named (system-wide) event.

Just store the handle to the anonymous event in a global variable, so that the thread can access it, and that's it.
Last edited on
Thanks kigar.

@seeplus

I have not touched into events, but that is great.

btw, I need to set it to LPVOID lpParameter otherwise it is throwing identifier expected.
Last edited on
I need to set it to LPVOID lpParameter otherwise it is throwing identifier expected.


What compiler are you using?
MinGW GCC.

If I use g++ it works w/o the lpParameter.

Last edited on
Ditch MinGW.
Last edited on
I think it's a C vs. C++ thing. In C, the parameter name can not be omitted in function definition, in C++ it can.

gcc is a C compiler, g++ is a C++ compiler. Rename the source file to foobar.c in MSVC, and you'll see the same behavior as in gcc.
Last edited on
Topic archived. No new replies allowed.