《TCP/IP网络编程》第19章

《TCP/IP网络编程》第19章

  • 内核对象(Kernel Objects)
    • 定义
    • 内核对象归操作系统所有
  • Windows线程创建
    • 进程与线程
    • 创建线程
    • 创建线程安全函数
  • 内核对象的2种状态
    • 内核对象状态及状态查看
    • WaitForSingleObject & WaitForMultipleObjects

内核对象(Kernel Objects)

定义

Windows操作系统创建并管理的资源(Resouce),进程、线程、文件、信号量、互斥量等。

不同资源管理方式有差异。

  • 文件管理,注册并更新文件相关的数据I/O位置、文件的打开模式(read or write)等。

  • 线程管理,注册并维护线程ID、线程所属进程等信息。

操作系统为了以记录相关信息的方式管理各种资源,在其内部生成数据块(结构体变量,内核对象)。

内核对象归操作系统所有

内核对象的创建、管理、销毁时机的决定等工作均由操作系统完成。

Windows线程创建

进程与线程

非显示创建线程的程序,单一线程模型的应用程序。
显示创建单独线程的程序,多线程模型的应用程序。
main函数的运行基于线程完成,进程是装有线程的篮子,实际的运行主体是线程。

创建线程

区分内核对象的整数型句柄(HANDLE),类似于Linux的文件描述符。

#include 
//失败NULL
HANDLE CreateThread(
	LPSECURITY_ATTRIBUTES lpThreadAttributes,//线程安全相关信息,NULL默认
	SIZE_T dwStackSize,//线程栈大小,0默认大小
	LPTHREAD_START_ROUTINE lpStartAddress,//函数
	LPVOID lpParameter,//参数
	DWORD dwCreationFlags, //线程创建后的行为,0线程创建后立即进入可执行状态
	LPDWORD lpThreadId //线程ID
);

Windows线程在main函数返回时销毁。

创建线程安全函数

#include 
//失败0
unitptr_t _beginthreadex( //unitptr_t,64位unsigned整型
	void *security,//线程安全相关信息,NULL默认
	unsigned stack_size,//线程栈大小,0默认大小
	unsigned (*start_address)(void *),//函数
	void *arglist,//参数
	unsigned initflag, //线程创建后的行为,0线程创建后立即进入可执行状态
	unsigned *thrdaddr //线程ID
);
//_beginthread会让创建线程时返回的句柄失效,以防止访问内核对象

thread1_win.c

#include 
#include 
#include  //_beginthreadex, _endthreadex

// WINAPI,Windows固有关键字,指定参数传递方向、分配的栈返回方式等函数调用相关规定。
unsigned WINAPI ThreadFunc(void *arg)
{
    int cnt = *((int *)arg);
    for (int i = 0; i < cnt; i++)
    {
        Sleep(1000);
        puts("running thread");
    }
    return 0;
}

int main(int argc, char *argv[])
{
    int param = 5;
    unsigned threadID;
    HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (void *)&param, 0, &threadID);
    if (hThread == 0)
    {
        puts("_beginthreadex() error");
        return -1;
    }

    Sleep(3000);

    puts("end of main");

    return 0;
}

/*
gcc thread1_win.c -o thread1_win -lws2_32
thread1_win.exe
*/

线程属于操作系统管理资源,伴随内核对象的创建,为了引用内核对象而返回句柄。

句柄区分内核对象,内核对象区分线程,线程句柄区分线程。

句柄的整数值在不同进程中可能重复,线程ID在跨进程范围内不会重复。

线程ID区分操作系统创建的所有线程。

内核对象的2种状态

应用程序实现过程中需要特别关注的信息被赋予某种“状态”。
线程终止状态又称signaled状态,未终止状态称为non-signaled状态。

内核对象状态及状态查看

进程或线程的内核对象初始状态是non-signaled状态,终止时是signaled状态。

通过boolean变量表示,初始值为FALSE(non-signaled状态),终止时(发生了事件,约定的情况)TRUE(signaled状态)。

WaitForSingleObject & WaitForMultipleObjects

#include 

//dwMilliseconds为INFINITE时阻塞直到终止
//终止(signaled状态)返回WAIT_OBJECT_0,超时返回WAIT_TIMEOUT
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);

该函数发生事件(变为signaled状态)返回时,有时会把相应对象再次改为non-signaled状态。

可以再次进入non-signaled状态的内核对象称为“auto-reset模式”的内核对象,不会自动跳转到non-signaled状态的内核对象称为“manual-reset模式”的内核对象。

#include 
//bWaitAll为TRUE,所有内核对象变为signaled状态时返回,
//bWaitAll为FALSE,任一内核对象变为signaled状态时返回
//dwMilliseconds为INFINITE时阻塞直到终止
//终止(signaled状态)返回WAIT_OBJECT_0,超时返回WAIT_TIMEOUT
DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lphHandles, BOOL bWaitAll, DWORD dwMilliseconds);

thread2_win.c

#include 
#include 
#include  //_beginthreadex, _endthreadex

unsigned WINAPI ThreadFunc(void *arg)
{
    int cnt = *(int *)arg;
    for (int i = 0; i < cnt; i++)
    {
        Sleep(1000);
        puts("running thread");
    }
    return 0;
}

int main(int argc, char *argv[])
{
    int param = 5;
    unsigned threadID;
    HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (void *)&param, 0, &threadID);
    if (hThread == 0)
    {
        puts("_beginthreadex() error");
        return -1;
    }

    DWORD wr;
    if ((wr = WaitForSingleObject(hThread, INFINITE)) == WAIT_FAILED)
    {
        puts("thread wait error");
        return -1;
    }

    printf("wait result: %s\n", (wr == WAIT_OBJECT_0) ? "signaled" : "time-out");

    puts("end of main");

    return 0;
}

/*
gcc thread2_win.c -o thread2_win -lws2_32
thread2_win.exe
*/

thread3_win.c

#include 
#include 
#include 

#define NUM_THREAD 50

long long num = 0;

unsigned WINAPI thread_inc(void *arg)
{
    for (int i = 0; i < 50000000; i++)
        num += 1;
    return 0;
}

unsigned WINAPI thread_des(void *arg)
{
    for (int i = 0; i < 50000000; i++)
        num -= 1;
    return 0;
}

int main(int argc, char *argv[])
{
    printf("size long long: %ld\n", sizeof(long long));
    HANDLE thread_id[NUM_THREAD];
    for (int i = 0; i < NUM_THREAD; i++)
        if (i % 2)
            thread_id[i] = (HANDLE)_beginthreadex(NULL, 0, thread_inc, NULL, 0, NULL);
        else
            thread_id[i] = (HANDLE)_beginthreadex(NULL, 0, thread_des, NULL, 0, NULL);

    WaitForMultipleObjects(NUM_THREAD, thread_id, TRUE, INFINITE);

    printf("result: %lld\n", num);
    return 0;
};

/*
gcc thread3_win.c -o thread3_win -lws2_32
thread3_win.exe
*/

你可能感兴趣的:(tcp/ip,C/C++,整理,网络,tcp/ip)