在做多线程开发时,互斥锁是必不可少的。但c语言不像c++11有标准的线程库,在各种编译器支持的平台都可以使用。而且跨平台开发中,在业务逻辑里写不同平台的兼容代码,容易造成过多的冗余,以及代码结构过于复杂的问题。为了提供一种统一的调用方式,封装一套跨平台的互斥锁还是有必要的。
一、接口设计:
1、数据结构:
使用宏区分平台,在Windows用winapi其他平台用pthread。为了灵活内存选择策略,直接定义字段在头文件,不采用pimp的方式。
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
/// <summary>
/// 互斥锁对象
/// </summary>
typedef struct {
#ifdef _WIN32
CRITICAL_SECTION mutex;
#else
pthread_mutex_t mutex;
#endif
} acf_mutex;
2、方法
(1)、初始化
互斥锁对象使用前需要初始化,传入互斥锁对象的指针。
/// <summary>
/// 初始化
/// </summary>
/// <param name="mutex">互斥锁对象的指针</param>
void acf_mutex_init(ac_mutex* mutex);
(2)、反初始化
互斥锁对象销毁前需要反初始化,传入互斥锁对象的指针。
/// <summary>
/// 反初始化
/// </summary>
/// <param name="mutex">互斥锁对象的指针</param>
void acf_mutex_deinit(acf_mutex *mutex);
(3)、加锁
进入互斥锁,多线程环境中调用此方法,第一个线程进入锁的后,其他线程会进入等待状态,直到解锁为止,其他线程才能进入。
/// <summary>
/// 加锁
/// </summary>
/// <param name="mutex">互斥锁对象的指针</param>
void acf_mutex_lock(acf_mutex* mutex);
(4)、尝试加锁
尝试进入锁而不等待,直接返回,返回1进入成功,0进入失败。
/// <summary>
/// 尝试加锁
/// </summary>
/// <param name="mutex">互斥锁对象的指针</param>
/// <returns>是否成功</returns>
int acf_mutex_trylock(acf_mutex* mutex);
(5)、解锁
执行完成互斥操作后,需要调用解锁退出,将资源让出给其他线程使用。
/// <summary>
/// 解锁
/// </summary>
/// <param name="mutex">互斥锁对象的指针</param>
void acf_mutex_unlock(acf_mutex* mutex);
二、使用例子
#include"Thread/acf_thread.h"
#include"Thread/acf_mutex.h"
#include<stdio.h>
static acf_mutex _mutex;
static void fun(void* arg) {
printf("thread %d request lock\n", (int)arg);
acf_thread_sleep(100);
//进入锁
acf_mutex_lock(&_mutex);
printf("thread %d got lock\n", (int)arg);
acf_thread_sleep(2000);
//退出锁
acf_mutex_unlock(&_mutex);
printf("thread %d leave lock\n", (int)arg);
}
int main(int argc, char** argv) {
//初始化互斥锁
acf_mutex_init(&_mutex);
//创建线程1
acf_thread thead1 = acf_thread_create(fun, 1);
//创建线程2
acf_thread thead2 = acf_thread_create(fun, 2);
//创建线程3
acf_thread thead3 = acf_thread_create(fun, 3);
acf_thread_wait_destroy(thead1);
acf_thread_wait_destroy(thead2);
acf_thread_wait_destroy(thead3);
//反初始化互斥锁
acf_mutex_deinit(&_mutex);
return 0;
}
三、完整代码