Create thread, suspend and resume thread, thread priority and terminate thread

Directory

1. Create a thread

CreateThread function:

Here is an example:

?edit

ThreadProc function explanation:

The essence of DWORD is unsigned long The essence of PVOID is void*

Second, the termination of the thread

1.WaitForSingleObject () function:

Examples are as follows:

2. ExitThread () function:

Examples are as follows:

3. TerminateThread () function:

4. CloseHandle() function:

5. Normal return 0;

3. Thread recovery and suspension

1. Suspend the thread:

①SuspendedThread() function:

Examples are as follows:

②The fifth parameter of CreateThread() is set to CEREATE_SUSPENDED

Fourth, the priority of the thread


1. Create thread

CreateThread function:

This function is used to create a new thread and run the specified function on it, and its return value is HANDLE type (handle), the prototype is as follows:

HANDLE CreateThread(
            LPSECURITY_ATTRIBUTES lpThreadAttributes,
            SIZE_T dwStackSize,
            LPTHREAD_START_ROUTINE lpStartAddress,
            LPVOID lpParameter,
            DWORD dwCreationFlags,
            LPDWORD lpThreadId
        );

The first parameter:
A pointer to a structure in the form of SECURITY_ATTRIBUTES, representing the security attributes of the thread kernel object
Windows 98 ignores this parameter, and setting it to NULL in Windows NT means using the default security attribute

The second parameter:
The initial stack size of this thread, in bytes, the default is 0, that is, the default size (1MB), in any case, the OS will dynamically extend the stack size

The third parameter:
Is a pointer to the thread function. The thread will execute from the entry point of this function.
The function name is unlimited, but it must be declared in the following form:
DWORD WINAPI ThreadProc(PVOID pParam);

The fourth parameter:
The parameter passed to the thread function (the parameter of the third function) is a pointer type.

The fifth parameter:
Thread creation flag, usually set to 0, the optional parameters are as follows:
0 (or CREATE_SUSPENDED): The default value, the thread function is executed immediately after the thread is created.

CREATE_SUSPENDED: After the thread is created, the execution of the thread is suspended, and the thread needs to be activated through ResumeThread.

CREATE_DETACHED: Create a detached thread without manually releasing thread resources.

STACK_SIZE_PARAM_IS_A_RESERVATION: Interpret the dwStackSize parameter as the reserved size of the stack.

CREATE_NEW_CONSOLE: Create a new console window, so that the thread runs in an independent console environment.

CREATE_UNICODE_ENVIRONMENT: Parse environment strings using the Unicode character set.

The sixth parameter:
A pointer to a DWORD that receives the identifier (ID) of the new thread
The ID number of the thread will be returned, and NULL is passed in to indicate that the thread ID number does not need to be returned

Here is an example:

#include <iostream>
#include <windows.h> //call the header file of windows API
using namespace std;

//Thread function, fixed format
DWORD WINAPI ThreadProc(PVOID lp){
    //The main body of the thread
    //…………
    return 0;
};


int main()
{
    CreateThread(NULL, 0, ThreadProc, NULL, 0, 0);

    return 0;
}

ThreadProc function explanation:

This function is the thread entry, ThreadProc is the same as lp, the name is optional, the ThreadProc function itself is used as the third parameter of the CreateThread function, and the function parameter is passed in from the fourth parameter of the CreateThread function

The essence of DWORD is unsigned long
The essence of PVOID is void*

Note: In a multi-threaded environment, global variables are shared by all threads, which means that multiple threads can access and modify these global variables at the same time. Because threads are concurrent, when a thread modifies the value of a global variable during execution, other threads may read the modified value when accessing the same global variable.

If a thread allocates memory on the heap using new and releases this memory during thread execution, other threads may encounter dangling pointers when accessing this memory. or problems with invalid memory access

Therefore, in multi-threaded programming, you must be very careful about shared resources, including global variables and dynamically allocated memory (such as new operations). Safe access to these resources by multiple threads should be ensured by appropriate synchronization mechanisms (such as mutexes, condition variables, etc.). This avoids potential race conditions and problems with accessing invalid memory.

When dealing with dynamic memory, it is best practice that the thread that created it is responsible for freeing the memory, not in other threads. In addition, you can use smart pointers (such as std::shared_ptr or std::unique_ptr) to manage dynamic memory, which can avoid the problem of manually releasing memory.

2. Thread termination

1.WaitForSingleObject() function:

The function prototype is as follows:

DWORD WaitForSingleObject(
HANDLE hHandle, // The handle of the kernel object to wait, here is the thread handle
DWORD dwMilliseconds // wait time in milliseconds, INFINITE means infinite wait
);

The second parameter dwMilliseconds indicates the waiting time in milliseconds. This parameter controls the behavior of the function when waiting for an object state change:

  • If the value of dwMilliseconds is INFINITE (-1), WaitForSingleObject blocks until the state of the kernel object changes.
  • If the value of dwMilliseconds is 0, the function checks the state of the kernel object immediately and returns without waiting.

Other positive integer values represent the number of milliseconds to wait. If the state of the object does not change within the specified time, the function returns a value indicating that the wait timed out.

Example:

#include <iostream>
#include <windows.h>
using namespace std;

DWORD WINAPI myProThread(PVOID lp)
{
    //ExitThread(0); Forcefully terminate the thread
    Sleep(5000); //Sleep under Windows is in milliseconds, here is sleep for 5 seconds
    return 0;
}

int main()
{
    DWORD id = 0;
    HANDLE handle = CreateThread(NULL, 0, myProThread, NULL, 0, &id);

    DWORD result = WaitForSingleObject(handle, 1); //Here is to set the waiting thread for 1 millisecond, in order to measure the timeout

    if (result == WAIT_OBJECT_0)
    {
        // Thread ends, you can continue processing
        cout << "end of thread" << endl;
    }
    else if (result == WAIT_TIMEOUT)
    {
        // Timeout, you can take corresponding measures
        cout << "timed out" << endl;
    }
    else if (result == WAIT_FAILED)
    {
        // The function call failed, you can get the error information through GetLastError()
        DWORD dwError = GetLastError();
        cout << "Thread error code is: " << dwError << endl;
    }

    cout << "The ID of this thread is:" << id << endl;

    CloseHandle(handle); //Close the thread handle

    return 0;
}

// Wait for the thread to end

2.ExitThread() function:

The ExitThread function can be used to directly exit the thread inside the thread function. However, it should be noted that using this function will terminate the execution of the thread, the destructor of the thread will not be called, and the resources occupied by the thread will not be released. This may cause resource leaks or program instability.

Can only be used within a thread, terminate the thread

Example:

code:

#include <iostream>
#include <windows.h>
using namespace std;

DWORD WINAPI myProThread(PVOID lp)
{
    ExitThread(0); //Forcibly terminate the thread
    Sleep(5000); //Sleep under Windows is in milliseconds, here is sleep for 5 seconds
    return 0;
}

int main()
{
    DWORD id = 0;
    HANDLE handle = CreateThread(NULL, 0, myProThread, NULL, 0, &id);

    DWORD result = WaitForSingleObject(handle, 1); //Here is to set the waiting thread for 1 millisecond, in order to measure the timeout

    if (result == WAIT_OBJECT_0)
    {
        // Thread ends, you can continue processing
        cout << "end of thread" << endl;
    }
    else if (result == WAIT_TIMEOUT)
    {
        // Timeout, you can take corresponding measures
        cout << "timed out" << endl;
    }
    else if (result == WAIT_FAILED)
    {
        // The function call failed, you can get the error information through GetLastError()
        DWORD dwError = GetLastError();
        cout << "Thread error code is: " << dwError << endl;
    }

    cout << "The ID of this thread is:" << id << endl;

    CloseHandle(handle); //Close the thread handle

    return 0;
}

// Wait for the thread to end

operation result:

3.TerminateThread() function:

The TerminateThread function can be used to forcibly terminate a thread. However, this function is not safe because it immediately terminates the execution of the thread, regardless of what the thread is doing. This can lead to unreleased resources, unstable states, and problems that can affect the entire process. It is recommended to avoid using this function.

Can be used outside the thread to terminate the specified thread

Here is no example, just how to use the function:

TerminateThread(hThread, 0); //The first parameter is the thread handle, the second parameter is the exit code (meaningless)

4.CloseHandle() function:

If you have a thread handle, you can use the CloseHandle function to close the thread handle. This will not terminate the thread, but will release the resources occupied by the handle. The main function of this function is to clean up the handle, not to terminate the thread.

Note: Before closing a thread handle, you should generally ensure that the thread has exited or at least is not referenced by the thread handle.

5. Normal return 0;

I won’t go into details.

3. Thread recovery and suspension

1. Suspend thread:

PS: 1 is added to the output of the following code to calculate the pending number.

①SuspendedThread() function:

The parameter is the thread handle, and the return value is the previous suspension number (that is, the number of times the function is called)

Example:

code:

#include <iostream>
#include <windows.h>
using namespace std;

DWORD WINAPI myProThread(PVOID lp)
{
    //ExitThread(0); //Forcibly terminate the thread
    Sleep(5000); //Sleep under Windows is in milliseconds, here is sleep for 5 seconds
    return 0;
}

int main()
{
    DWORD id = 0;
    HANDLE handle = CreateThread(NULL, 0, myProThread, NULL, 0, & amp;id); //The fifth parameter indicates that the thread is suspended when the creation is completed

    cout << "The ID of this thread is:" << id << endl;

    DWORD result = WaitForSingleObject(handle, 3000); //Here is to set the waiting thread for 1 millisecond, in order to measure the timeout

    
    // suspend thread
    DWORD suspendCount = SuspendThread(handle);
    
    cout << "The initial suspend count is: " << suspendCount + 1 << endl;

    // Check if the thread is suspended successfully
    if (suspendCount != -1) {
        cout << "thread is suspended" << endl;
    } else {
        cerr << "Unable to suspend thread" << endl;
    }

    if (result == WAIT_OBJECT_0)
    {
        // Thread ends, you can continue processing
        cout << "end of thread" << endl;
    }
    else if (result == WAIT_TIMEOUT)
    {
        // Timeout, you can take corresponding measures
        cout << "timed out" << endl;
    }
    else if (result == WAIT_FAILED)
    {
        // The function call failed, you can get the error information through GetLastError()
        DWORD dwError = GetLastError();
        cout << "Thread error code is: " << dwError << endl;
    }


    CloseHandle(handle); //Close the thread handle


    return 0;
}

result:

②The fifth parameter of CreateThread() is set to CEREATE_SUSPENDED

The code is the same as above, except that when creating a thread, the fifth parameter is set to CEREATE_SUSPENDED

result:

Four, thread priority

Under Windows, C++ programs can use the Thread Library (Thread Library) to create and manage threads. In Windows, thread priority is used to determine how the operating system schedules threads when there are multiple threads to execute. Windows provides a set of functions and constants to set and get a thread’s priority. The following is important information about C++ thread priorities under Windows:

1. **Thread priority range:** In Windows systems, the priority range of threads is usually from 0 (lowest priority) to 31 (highest priority).

2. **Default priority:** When a new thread is created, it will inherit the priority of the thread that created it by default.

3. **Set thread priority:** You can use the `SetThreadPriority` function to set the thread priority. The prototype of this function is as follows:

BOOL SetThreadPriority(
HANDLE hThread,
int nPriority
);

– `hThread`: Handle of the thread whose priority is to be set.
– `nPriority`: The priority to set, can be one of the following constants:
– `THREAD_PRIORITY_IDLE`
– `THREAD_PRIORITY_LOWEST`
– `THREAD_PRIORITY_BELOW_NORMAL`
– `THREAD_PRIORITY_NORMAL`
– `THREAD_PRIORITY_ABOVE_NORMAL`
– `THREAD_PRIORITY_HIGHEST`
– `THREAD_PRIORITY_TIME_CRITICAL`

4. **Get Thread Priority:** You can use the `GetThreadPriority` function to get the current priority of a thread. The prototype of this function is as follows:

int GetThreadPriority(
HANDLE hThread
);

– `hThread`: The thread handle whose priority is to be queried.

It should be noted that although thread scheduling can be affected by setting thread priority, excessive use of priority may cause problems, such as starvation, unfair scheduling, etc. Proper use of synchronization mechanisms and appropriate thread priorities to ensure program stability and predictability are part of good multithreaded programming practice.

In actual development, unless you have a clear need, it is generally not recommended to change the priority of threads frequently, but let the operating system manage thread scheduling by itself to ensure the smooth operation of the entire system.