线程的第一次接触

一. 产生一个线程

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程的安全属性,NULL表示使用缺省值。
  DWORD dwStackSize,                        // 线程的堆栈,0 表示用缺省大小: 1M
  LPTHREAD_START_ROUTINE lpStartAddress,    // 线程的起始地址,这里是一个函数指针
  LPVOID lpParameter,                       // 上面线程函数的参数
  DWORD dwCreationFlags,                    // 允许你产生一个暂时挂起的线程,默认是"立即执行"
  LPDWORD lpThreadId                        // 新线程的ID会被传回到这里
);
//返回值:如果成功,传回一个handle,表示一个新线程;否则返回一个FALSE
CreateThread()返回两个值,用以识别这个新线程。一个值是返回值 HANDLE,大部分与线程有关的API函数都需要它;第二个值是线程ID,但是你不可以根据线程 ID 来获得其 handle。

二. 释放核心对象

BOOL CloseHandle(
  HANDLE hObject   // handle to object
);
//返回值:如果成功返回TRUE,否者返回FASLE

所有的核心对象都保持了一个引用计数,以记录有多少个 handles 对应到此对象。当你调用 CloseHandle()时,引用计数便递减 1。

线程对象默认引用计数是 2,当你调用 CloseHandle()时,引用计数便递减 1,当线程结束时,引用计数再减 1,如果值变成 0,对象会自动被操作系统销毁。

其实调用这个函数,只不过表示希望自己和此核心对象不再有任何瓜葛。CloseHandle()唯一做的事情就是把引用计数减 1

三. 线程结束代码

BOOL GetExitCodeThread(
  HANDLE hThread,      // CreateThread()返回的线程 handle
  LPDWORD lpExitCode   // 指向一个DWORD,用以接受结束代码
);
//返回值:如果成功返回TRUE,否者返回FASLE

如果线程已结束,那么结束码会放在lpExitCode中,如果线程尚未结束,lpExitCode 的值为 STILL_ACTIVE。

要注意,千万不要用这个函数的返回值来判断线程是运行还是结束

四. 结束一个线程

VOID ExitThread(
  DWORD dwExitCode   // 指定此线程的结束码
);
//没有返回值
注意,任何代码若放在此行之下,都不会被执行。

五. 示例代码

#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>

DWORD WINAPI ThreadFunc(LPVOID);

int main()
{
    HANDLE hThrd1;
    HANDLE hThrd2;
    DWORD exitCode1 = 0;
    DWORD exitCode2 = 0;
    DWORD threadId;
    
    hThrd1 = CreateThread(NULL,
        0,
        ThreadFunc,
        (LPVOID)1,
        0,
        &threadId );
    if (hThrd1)
        printf("Thread 1 launched\n");

    hThrd2 = CreateThread(NULL,
        0,
        ThreadFunc,
        (LPVOID)2,
        0,
        &threadId );
    if (hThrd2)
        printf("Thread 2 launched\n");


    // Keep waiting until both calls to
    // GetExitCodeThread succeed AND
    // neither of them returns STILL_ACTIVE.
    // This method is not optimal - we'll
    // see the correct way in Chapter 3.
    for (;;)
    {
        printf("Press any key to exit..\n");
        getch();

        GetExitCodeThread(hThrd1, &exitCode1);
        GetExitCodeThread(hThrd2, &exitCode2);
        if ( exitCode1 == STILL_ACTIVE )
            puts("Thread 1 is still running!");
        if ( exitCode2 == STILL_ACTIVE )
            puts("Thread 2 is still running!");
        if ( exitCode1 != STILL_ACTIVE
            && exitCode2 != STILL_ACTIVE )
            break;
    }

    CloseHandle(hThrd1);
    CloseHandle(hThrd2);

    printf("Thread 1 returned %d\n", exitCode1);
    printf("Thread 2 returned %d\n", exitCode2);

    return EXIT_SUCCESS;
}


/*
 * Take the startup value, do some simple math on it,
 * and return the calculated value.
 */
DWORD WINAPI ThreadFunc(LPVOID n)
{
    Sleep((DWORD)n*1000*2);
    return (DWORD)n * 10;
}
说明:

主线程结束会使得程序中的所有线程都被迫结束,其他线程没有机会做清理工作。比如,如果 main() 结束了,那么在main()里创建的其它线程都将被迫结束。

你可能感兴趣的:(Math,thread,object,null,attributes,winapi)