在c语言中使用多线程

目前项目是在windows环境下使用的MSVC来编译c语言文件

所以需要包含Windows.h头文件。如果是gcc需要包含pthread.h头文件

目前只学习了在visual studio中使用包含Windows.h头文件的方法

使用多线程需要考虑是否会多个线程同时修改共有的数据,如果有此种场景需要加入线程锁

我在c语言彩票系统主要使用下面两个函数

创建线程锁

CreatedMutex函数

下面是创建线程锁的函数原形

HANDLE CreateMutex(
    LPSECURITY_ATTRIBUTES lpMutexAttributes,  // 安全属性
    BOOL bInitialOwner,                       // 创建者是否初始拥有锁
    LPCSTR lpName                             // 互斥锁名称
);

下面分别解释三个参数

第一个参数LPSECURITY_ATTRIBUTES类型

此类型为下面安全属性的结构体指针类型

lpMutexAttributes其作用是指定互斥锁的安全描述符,控制句柄是否可继承

常用值为NULL,填入NULL则不可被子线程继承

typedef struct _SECURITY_ATTRIBUTES {
    DWORD nLength;
    LPVOID lpSecurityDescriptor;
    BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;

第二参数BOOL类型

bInitialOwner其作用是指定线程是否立即拥有互斥锁

FLASE:创建后锁处于未拥有状态

TRUE:创建者立即拥有,需要手动释放此锁,如果没有释放会使得创建了此锁的线程立刻上锁

通常用FALSE通过WaitForSingleObject来竞争锁

第三个参数LPCSTR类型

此类型为指向常量字符串的指针类型

lpName其作用是为互斥锁命名,允许跨进程使用

常用值为:NULL,创建匿名锁,仅限当前进程使用,如果为其命名“myMutex”则可以跨进程访问

使用流程

1.创建锁

HANDLE mutex = CreateMutex(NULL, FALSE, NULL);

2.加锁

WaitForSingleObject(mutex, INFINITE);  // 等待锁

3.解锁

ReleaseMutex(mutex);  // 释放锁

4.清理

CloseHandle(mutex);  // 关闭句柄

创建线程

CreateThread函数

下面是创建线程函数原形

HANDLE CreateThread(
    LPSECURITY_ATTRIBUTES lpThreadAttributes,  // 线程的安全属性
    SIZE_T dwStackSize,                        // 线程栈大小
    LPTHREAD_START_ROUTINE lpStartAddress,     // 线程函数地址
    LPVOID lpParameter,                        // 传递给线程的参数
    DWORD dwCreationFlags,                     // 创建标志
    LPDWORD lpThreadId                         // 返回线程 ID
);

下面分别解释各个参数

1.第一个参数LPSECURITY_ATTRIBUTES类型

其作用与上面的创建线程锁第一个参数类似,控制线程句柄是否可被继承

填入NULL则不允许被继承,一般填NULL即可

2.第二个SIZE_T类型,无符号整数

其作用指定线程的栈空间大小

通常使用0为1MB大小

如果线程需要大量局部变量则设置更大值

3.第三个参数LPTHREAD_START_ROUTINE类型

其作用指向线程执行的函数,签名必须是DWORD WINAPI ThreadFunc(LPVOID)

类型就是函数指针,即线程函数名

4.第四个参数lpParameter 通用指针类型,实际上就是void*

其作用是传递给线程函数的参数,可以是任意数据的地址。

常用NULL,线程不需要参数,如果传入了数据,则需要在线程内强制转换使用

5.第五个参数DWORD类型(32位无符号整型)

其作用是控制创建后的行为

0为线程创建后立即运行,4为线程创建后暂停,需要调用ResumeThread来启动线程

如果想先创建线程但延迟执行则可以使用CREATE_SUSPENDED函数

其他值没有研究还

6.第六个参数LPDWORD类型 (其类型是指向DWORD的一个指针)

作用是返回新线程的ID

NULL则是不需要线程ID,否则就通过指针修改其接收值

DWORD threadId;
CreatedTread(NULL, 0, threadFunc, NULL, 0, &threadId);