Thread creation, thread suspension and resumption, thread priority and thread termination

Table of contents

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*

2. Termination of 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:

 ②Set the fifth parameter of CreateThread() to CEREATE_SUSPENDED

 4. Thread priority


1. Create a thread

CreateThread function:

        This function is used to create a new thread and run the specified function on it. Its return value is of type HANDLE (handle), and 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, indicating the security attributes of the thread kernel object.
                Windows 98 ignores this parameter. In Windows NT, setting it to NULL means using the default security attributes.

        The second parameter:
            the initial stack size of the thread, in bytes, the default is 0, that is, the default size (1MB) is used. 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.
            There is no restriction on the function name, 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:
            the creation flag of the thread, usually set to 0, the optional parameters are as follows:
                0 (or CREATE_SUSPENDED): default value, the thread function is executed immediately after the thread is created.

                CREATE_SUSPENDED: Pause the execution of the thread after creating the thread, and you need to activate the thread through ResumeThread.

                CREATE_DETACHED: Creates 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: Creates a new console window so that the thread runs in an independent console environment.

                CREATE_UNICODE_ENVIRONMENT: Use the Unicode character set to parse environment strings.

        The sixth parameter:
            a pointer to a DWORD type, used to receive the identifier (ID) of the new thread
            and return the ID number of the thread. Passing in NULL means that the thread ID number does not need to be returned.
 

 Here is an example:

#include <iostream>
#include <windows.h> //调用windows API的头文件
using namespace std;

//线程函数,格式固定
DWORD WINAPI ThreadProc(PVOID lp){
    //线程的主体
    //…………
    return 0;
};


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

    return 0;
}

ThreadProc function explanation:

        This function is the thread entrance. ThreadProc is the same as lp. The name is arbitrary. The ThreadProc function itself is used as the third parameter of the CreateThread function. This function parameter is passed in by 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 one 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 newallocates memory on the heap and releases the memory while the thread is executing, other threads may encounter dangling pointers or invalid memory access problems when accessing the memory.

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

When dealing with dynamic memory, it's best practice to have the thread that created it be responsible for freeing the memory, rather than freeing it in other threads. Additionally, dynamic memory can be managed using smart pointers (e.g. std::shared_ptror ), which avoids the problem of manually freeing memory.std::unique_ptr

2. Termination of thread

1.WaitForSingleObject() function:

The function prototype is as follows:

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

The second parameter dwMillisecondsrepresents the waiting time, in milliseconds. This parameter controls the function's behavior when waiting for an object's state to change:

  • If dwMillisecondsthe value of is INFINITE(-1), it WaitForSingleObjectwill block until the state of the kernel object changes.
  • If dwMillisecondsthe value of is 0, the function immediately checks the status of the kernel object and returns without waiting.

Other positive integer values ​​represent the number of milliseconds to wait. If the object's state does not change within the specified time, the function returns a value indicating the wait timeout. 

Examples are as follows:

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

DWORD WINAPI myProThread(PVOID lp)
{
    //ExitThread(0);    强制终止线程
    Sleep(5000);    //Windows 下 Sleep 以毫秒为单位,这里是休眠 5 秒
    return 0;
}

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

    DWORD result = WaitForSingleObject(handle, 1);    //这里是设定等待线程1毫秒,为了测定超时

    if (result == WAIT_OBJECT_0)
    {
        // 线程结束,可以继续处理
        cout << "线程结束" << endl;
    }
    else if (result == WAIT_TIMEOUT)
    {
        // 超时,可以采取相应的措施
        cout << "超时了" << endl;
    }
    else if (result == WAIT_FAILED)
    {
        // 函数调用失败,可以通过 GetLastError() 获取错误信息
        DWORD dwError = GetLastError();
        cout << "线程错误代码为:" << dwError << endl;
    }

    cout << "该线程的ID是:" << id << endl;

    CloseHandle(handle);    //关闭线程句柄

    return 0;
}

// 等待线程结束

2.ExitThread() function :

ExitThreadFunctions can be used to exit a thread directly inside a thread function. However, it should be noted that using this function will terminate the execution of the thread, will not call the thread's destructor, and will not release the resources occupied by the thread. This may lead to resource leaks or program instability.

Can only be used within a thread, terminate the thread

Examples are as follows:

Code:

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

DWORD WINAPI myProThread(PVOID lp)
{
    ExitThread(0);   //强制终止线程
    Sleep(5000);    //Windows 下 Sleep 以毫秒为单位,这里是休眠 5 秒
    return 0;
}

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

    DWORD result = WaitForSingleObject(handle, 1);    //这里是设定等待线程1毫秒,为了测定超时

    if (result == WAIT_OBJECT_0)
    {
        // 线程结束,可以继续处理
        cout << "线程结束" << endl;
    }
    else if (result == WAIT_TIMEOUT)
    {
        // 超时,可以采取相应的措施
        cout << "超时了" << endl;
    }
    else if (result == WAIT_FAILED)
    {
        // 函数调用失败,可以通过 GetLastError() 获取错误信息
        DWORD dwError = GetLastError();
        cout << "线程错误代码为:" << dwError << endl;
    }

    cout << "该线程的ID是:" << id << endl;

    CloseHandle(handle);    //关闭线程句柄

    return 0;
}

// 等待线程结束

 operation result:

 

3.TerminateThread() function :

TerminateThreadFunctions can be used to forcefully terminate a thread. However, this function is unsafe because it immediately terminates the thread's execution 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

There are no examples here, only 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 handle to the thread, you can use CloseHandlethe function to close the thread handle. This does not terminate the thread, but it releases the resources held by the handle. The main function of this function is to clean up the handle, not to terminate the thread.

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

5. Normal return 0;

No further details will be given.

3. Thread recovery and suspension

1. Suspend the thread:

PS: The following code output adds 1 when calculating 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)

Examples are as follows:

Code:

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

DWORD WINAPI myProThread(PVOID lp)
{
    //ExitThread(0);   //强制终止线程
    Sleep(5000);    //Windows 下 Sleep 以毫秒为单位,这里是休眠 5 秒
    return 0;
}

int main()
{
    DWORD id = 0;
    HANDLE handle = CreateThread(NULL, 0, myProThread, NULL, 0, &id);   //第五个参数表示创建完成时挂起线程

    cout << "该线程的ID是:" << id << endl;

    DWORD result = WaitForSingleObject(handle, 3000);    //这里是设定等待线程1毫秒,为了测定超时

    
    // 挂起线程
    DWORD suspendCount = SuspendThread(handle);
    
    cout << "初始挂起数为:"  << suspendCount + 1 << endl;

    // 检查是否成功挂起线程
    if (suspendCount != -1) {
        cout << "线程已挂起" << endl;
    } else {
        cerr << "无法挂起线程" << endl;
    }

    if (result == WAIT_OBJECT_0)
    {
        // 线程结束,可以继续处理
        cout << "线程结束" << endl;
    }
    else if (result == WAIT_TIMEOUT)
    {
        // 超时,可以采取相应的措施
        cout << "超时了" << endl;
    }
    else if (result == WAIT_FAILED)
    {
        // 函数调用失败,可以通过 GetLastError() 获取错误信息
        DWORD dwError = GetLastError();
        cout << "线程错误代码为:" << dwError << endl;
    }


    CloseHandle(handle);    //关闭线程句柄


    return 0;
}

result:

 ②Set the fifth parameter of CreateThread() to CEREATE_SUSPENDED

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

result:

 4. Thread priority

Under Windows, C++ programs can use the 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 the priority of a thread. 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 inherits 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`: The handle of the thread to set the priority.
     - `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_HI GHEST`
     - `THREAD_PRIORITY_TIME_CRITICAL`

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


   int GetThreadPriority(
     HANDLE hThread
   );


 - `hThread`: The thread handle to query the priority.

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

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

Guess you like

Origin blog.csdn.net/weixin_72758935/article/details/132093463