目录
概述
在多线程并发且存在改写和访问公共数据的情况下,需要保证改写和访问数据对象是准确的,同一时间内只能有一个线程进行对公共数据的改写,保证数据的写正确,同时在改写数据同时,不能访问数据,保证数据的读正确。锁为了公共数据的操作提供了安全的保护机制。C/C++语言有互斥锁、条件锁、递归锁、自旋锁、读写锁,以下我们从锁的使用流程和使用示例逐一展开讲解。
C互斥锁
头文件
#include <pthread.h>
数据类型
pthread_mutex_t
声明
pthread_mutex_t g_mutex;
初始化
1、动态初始化
pthread_mutex_init(&lock, NULL); // 成功返回0,失败返回非0
2、静态初始化
1)pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
加锁
// 普通加锁,重复加锁会阻塞进程
int pthread_mutex_lock (pthread_mutex_t *__mutex);
// 重复加锁不阻塞进程
int pthread_mutex_trylock (pthread_mutex_t *__mutex);
// 带有超时功能加锁
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abs_timeout);
解锁
int pthread_mutex_unlock (pthread_mutex_t *__mutex);
去初始化
int pthread_mutex_destroy(pthread_mutex_t *mutex);
示例
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t g_mutex;
int g_data = 0;
int do_num = 10;
void* thread1_func(void* data)
{
int i = 0;
for (i = 0; i < 10; i++){
pthread_mutex_lock(&g_mutex);
printf("thread1_func g_data:%d\n", g_data);
g_data++;
pthread_mutex_unlock(&g_mutex);
}
return NULL;
}
void* thread2_func(void* data)
{
int i = 0;
for (i = 0; i < 10; i++){
pthread_mutex_lock(&g_mutex);
printf("thread2_func g_data:%d\n", g_data);
g_data--;
pthread_mutex_unlock(&g_mutex);
}
return NULL;
}
int main(int argc, char* argv[])
{
// 初始化
pthread_mutex_init(&g_mutex, NULL);
// 创建2个线程
pthread_t thread1;
pthread_t thread2;
pthread_create(&thread1, NULL, thread1_func, NULL);
pthread_create(&thread2, NULL, thread2_func, NULL);
// 等待线程退出
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
// 去初始化
pthread_mutex_destroy(&g_mutex);
printf("test done \n");
return 0;
}
C条件锁
条件锁是条件变量结合普通互斥锁实现等待和唤醒的一个机制,主要应用场景为生产者和消费者对资源操作的应用。
头文件
#include <pthread.h>
数据类型
// 互斥锁数据类型
pthread_mutex_t
// 条件变量数据类型
pthread_cond_t
声明
pthread_mutex_t g_mutex;
pthread_cond_t g_condition;
初始化
pthread_mutex_init(&g_mutex, NULL);
pthread_cond_init(&g_condition, NULL);
条件锁等待
pthread_mutex_lock(&g_mutex);
// 等待唤醒前解锁,唤醒线程会上锁,然后在解锁
pthread_cond_wait(&g_condition, &g_mutex);
pthread_mutex_unlock(&g_mutex);
条件锁唤醒
pthread_cond_broadcast(&g_condition);
条件锁销毁
// 销毁互斥锁
pthread_mutex_destroy(&g_mutex);
// 销毁条件变量
pthread_cond_destroy(&g_condition);
示例
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
// 生产者条件锁声明
pthread_mutex_t g_productLock;
pthread_cond_t g_productCondition;
// 消费者条件锁声明
pthread_mutex_t g_consumerLock;
pthread_cond_t g_consumerCondition;
// 定时线程回调函数类型
// typedef void* (ThreadCallback*)(void* data)
// 消息定义
int g_msgs = 0;
int g_msgsNum = 10;
pthread_mutex_t g_msgLock;
static int GetMsgs()
{
int msg = 0;
pthread_mutex_lock(&g_msgLock);
msg = g_msgs;
pthread_mutex_unlock(&g_msgLock);
return msg;
}
static void ProductMsg()
{
printf("Product msgs:%d\n", g_msgs);
pthread_mutex_lock(&g_msgLock);
g_msgs++;
pthread_mutex_unlock(&g_msgLock);
}
static void ConsumeMsg()
{
printf("consume msgs:%d\n", g_msgs);
pthread_mutex_lock(&g_msgLock);
g_msgs--;
pthread_mutex_unlock(&g_msgLock);
}
// 消息生成线程
static void* ProductMsgThread(void* data)
{
int i = 0;
int msgs = GetMsgs();
for (i = 0; i < g_msgsNum; i++){
// 有消息时,不生产,等待唤醒
msgs = GetMsgs();
if (msgs > 0){
pthread_mutex_lock(&g_consumerLock);
// 唤醒消费者进行消费
pthread_cond_broadcast(&g_consumerCondition);
pthread_cond_wait(&g_productCondition, &g_consumerLock);
pthread_mutex_unlock(&g_consumerLock);
} else {
ProductMsg();
}
sleep(1);
}
pthread_cond_broadcast(&g_consumerCondition);
printf("ProductMsgThread end \n");
}
// 消息消费线程
static void* ConsumeMsgThread(void* data)
{
int i = 0;
int msgs = GetMsgs();
for (i = 0; i < g_msgsNum; i++){
// 有消息时,不生产,等待唤醒
msgs = GetMsgs();
if (msgs == 0){
pthread_mutex_lock(&g_productLock);
// 唤醒消费者进行消费
pthread_cond_broadcast(&g_productCondition);
pthread_cond_wait(&g_consumerCondition, &g_productLock);
pthread_mutex_unlock(&g_productLock);
} else {
ConsumeMsg();
}
sleep(1);
}
g_msgs = 0;
pthread_cond_broadcast(&g_productCondition);
printf("ConsumeMsgThread end i:%d\n", i);
}
int main(int argc, char*argv[])
{
//初始化条件锁
pthread_mutex_init(&g_productLock, NULL);
pthread_mutex_init(&g_consumerLock, NULL);
pthread_cond_init(&g_productCondition, NULL);
pthread_cond_init(&g_consumerCondition, NULL);
// 消息生产者和消息消费者创建
pthread_t productThread;
pthread_t consumeThread;
pthread_create(&productThread, NULL, ProductMsgThread, NULL);
pthread_create(&consumeThread, NULL, ConsumeMsgThread, NULL);
// 等待生产和消费
sleep(10);
// 条件锁销毁
pthread_mutex_destroy(&g_productLock);
pthread_mutex_destroy(&g_consumerLock);
pthread_cond_destroy(&g_productCondition);
pthread_cond_destroy(&g_consumerCondition);
// 等待线程退出
pthread_join(productThread, NULL);
pthread_join(consumeThread, NULL);
printf("test end\n");
return 0;
}
C读写锁
使用场景
读共享数据次数比写共享的次数多,
头文件
#include <pthread.h>
数据类型
pthread_rwlock_t;
声明
pthread_rwlock_t g_rwlock;
初始化
pthread_rwlock_init(&g_rwlock, NULL);
读写加锁
// 读加锁
pthread_rwlock_rdlock(&g_rwlock);
// 写加锁
pthread_rwlock_wrlock(&g_rwlock);
读写解锁
pthread_rwlock_unlock(&g_rwlock);
读写锁销毁
pthread_rwlock_destroy(&g_rwlock);
示例
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
// 读写锁声明
pthread_rwlock_t g_rwlock;
// 全局共享数据
int g_data = 0;
// 读写数据操作次数
int g_rwNum = 10;
static void* WriteThread(void* data)
{
int i = 0;
for (i = 0; i < g_rwNum; i++){
pthread_rwlock_wrlock(&g_rwlock);
g_data++;
printf("WriteThread g_data:%d\n", g_data);
pthread_rwlock_unlock(&g_rwlock);
int a = rand()%5;
usleep(a);
}
}
static void* ReadThread1(void* data)
{
int i = 0;
for (i = 0; i < g_rwNum; i++){
pthread_rwlock_rdlock(&g_rwlock);
printf("ReadThread1 g_data:%d\n", g_data);
pthread_rwlock_unlock(&g_rwlock);
int b = rand()%5;
usleep(b);
}
}
static void* ReadThread2(void* data)
{
int i = 0;
for (i = 0; i < g_rwNum; i++){
pthread_rwlock_rdlock(&g_rwlock);
printf("ReadThread2 g_data:%d\n", g_data);
pthread_rwlock_unlock(&g_rwlock);
int c = rand()%5;
usleep(c);
}
}
int main(int argc, char* argv[])
{
// 读写锁初始化
pthread_rwlock_init(&g_rwlock, NULL);
// 创建写线程
pthread_t writeThreadId;
pthread_create(&writeThreadId, NULL, WriteThread, NULL);
// 创建读线程1
pthread_t readThreadId1;
pthread_create(&readThreadId1, NULL, ReadThread1, NULL);
// 创建读线程2
pthread_t readThreadId2;
pthread_create(&readThreadId2, NULL, ReadThread2, NULL);
// 等待线程退出
pthread_join(writeThreadId, NULL);
pthread_join(readThreadId1, NULL);
pthread_join(readThreadId2, NULL);
// 读写锁的销毁
pthread_rwlock_destroy(&g_rwlock);
printf("test end \n");
}