C语言pthread读写锁

本文介绍了POSIX线程标准中的pthread读写锁机制,详细解释了读写锁的工作原理,包括读写锁的特性、基本函数及应用场景,并提供了一个简单的示例程序。

Pthread 是 POSIX threads 的简称,是POSIX的 线程标准 。pthread读写锁把对共享资源的访问者分为读者和写者,读者只对共享资源进行读访问,写者只对共享资源进行写操作。在互斥机制,读者和写者都需要独立独占互斥量以独占共享资源,在读写锁机制下,允许同时有多个读者读访问共享资源,只有写者才需要独占资源。相比互斥机制,读写机制由于允许多个读者同时读访问共享资源,进一步提高了多线程的并发度。

1.读写锁机制:

  • 写者:写者使用写锁,如果当前没有读者,也没有其他写者,写者立即获得写锁;否则写者将等待,直到没有读者和写者。
  • 读者:读者使用读锁,如果当前没有写者,读者立即获得读锁;否则读者等待,直到没有写者。 

2.读写锁特性:

  • 同一时刻只有一个线程可以获得写锁,同一时刻可以有多个线程获得读锁。
  • 读写锁出于写锁状态时,所有试图对读写锁加锁的线程,不管是读者试图加读锁,还是写者试图加写锁,都会被阻塞。
  • 读写锁处于读锁状态时,有写者试图加写锁时,之后的其他线程的读锁请求会被阻塞,以避免写者长时间的不写锁。

3.读写锁基本函数:

        头文件: # include<pthread.h>

  • 读写锁初始化:

        int pthread_rwlock_init(pthread_rwlock_t * rwlock,  const pthread_rwlockattr_t *  attr);

        该函数第一个参数为读写锁指针,第二个参数为读写锁属性指针。函数按读写锁属性对读写锁进行初始化。

  • 加读锁:

        int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

        该函数参数为读写锁指针。函数用于对读写锁加读锁。

  • 加写锁:

        int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

        该函数参数为读写锁指针。函数用于对读写锁加写锁。

  • 释放读写锁:

        int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

        该函数参数为读写锁指针。函数用于释放读写锁,包括读锁与写锁。

  • 销毁读写锁:

        int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

        该函数参数为读写锁指针。函数用于销毁读写锁。

 4.牛刀小试:

        示例使用读写锁,对共享资源data进行读写同步,线程readerM,readerN为读者线程,线程writerA,writerB为写者线程。       

#include <iostream>     
#include <pthread.h>      
#include <unistd.h>            

pthread_t t1;           //pthread_t变量t1,用于获取线程1的ID
pthread_t t2;           //pthread_t变量t2,用于获取线程2的ID
pthread_rwlock_t rwlock;             //声明读写锁
int data=1;                          //共享资源
void* readerM(void* arg)
{
	while(1)
	{
	pthread_rwlock_rdlock(&rwlock);    //读者加读锁
	printf("M 读者读出: %d \n",data);   //读取共享资源
	pthread_rwlock_unlock(&rwlock);    //读者释放读锁
	sleep(1200);
	}
	return NULL;
}
void* readerN(void* arg)
{
	while(1)
	{
	pthread_rwlock_rdlock(&rwlock);
	printf(" N读者读出: %d \n",data);
	pthread_rwlock_unlock(&rwlock);
	Sleep(700);
	}
	return NULL;
}
void* writerA(void* arg)
{
	while(1)
	{
	pthread_rwlock_wrlock(&rwlock);      //写者加写锁
	data++;                              //对共享资源写数据
	printf("	A写者写入: %d\n",data);
	pthread_rwlock_unlock(&rwlock);      //释放写锁
	sleep(2000);
	}
	return NULL;
}
void* writerB(void* arg)
{
	while(1)
	{
	pthread_rwlock_wrlock(&rwlock);
	 data++;
	printf("	B写者写入: %d\n",data);
	pthread_rwlock_unlock(&rwlock);
	Sleep(2000);
	}
	return NULL;
}
void main(int argc,char** argv)
{
	pthread_rwlock_init(&rwlock, NULL);   //初始化读写锁
    
    pthread_create(&t1,NULL,readerM,NULL);
	pthread_create(&t1,NULL,readerN,NULL);
	pthread_create(&t2,NULL,writerA,NULL);
	pthread_create(&t2,NULL,writerB,NULL);

	pthread_rwlock_destroy(&rwlock);      //销毁读写锁

	sleep(10000000);
	return;
}
在C语言中,读写锁(`pthread_rwlock_t`)是一种同步机制,用于控制多个线程对共享资源的访问。它允许同时有多个读线程访问资源,但在有写线程访问时,会阻塞所有其他读写线程。这种机制适用于读操作远多于写操作的场景,可以提高并发性能。 ### 初始化读写锁 在使用读写锁之前,需要先初始化它。可以通过静态初始化或动态初始化来完成。 ```c #include <pthread.h> pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; // 静态初始化 ``` 或者动态初始化: ```c pthread_rwlock_t rwlock; pthread_rwlock_init(&rwlock, NULL); // 动态初始化 ``` ### 获取和释放读写锁 读写锁提供了两种加锁方式:读锁和写锁。 - **读锁**:多个线程可以同时获取读锁,但不能有写锁存在。 - **写锁**:只有一个线程可以获取写锁,且此时不能有其他任何读写锁存在。 获取读锁: ```c int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); ``` 获取写锁: ```c int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); ``` 释放锁: ```c int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); ``` ### 销毁读写锁 当不再需要读写锁时,应调用 `pthread_rwlock_destroy` 函数来销毁它。 ```c int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); ``` ### 示例代码 以下是一个简单的示例,展示了如何在多个线程中使用读写锁来保护一个共享变量 `counter`,其中一些线程负责读取,另一些线程负责写入。 ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> int counter = 0; pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; void *th_write(void *arg) { while (1) { pthread_rwlock_wrlock(&rwlock); // 获取写锁 int t = counter; printf("write %x : counter=%d ++counter=%d\n", (int)pthread_self(), t, ++counter); pthread_rwlock_unlock(&rwlock); // 释放写锁 usleep(100000); // 睡眠 100 毫秒 } return NULL; } void *th_read(void *arg) { while (1) { pthread_rwlock_rdlock(&rwlock); // 获取读锁 printf("read %x : %d\n", (int)pthread_self(), counter); pthread_rwlock_unlock(&rwlock); // 释放读锁 usleep(50000); // 睡眠 50 毫秒 } return NULL; } int main() { pthread_t writers[3], readers[5]; // 创建 3 个写线程 for (int i = 0; i < 3; i++) { pthread_create(&writers[i], NULL, th_write, NULL); } // 创建 5 个读线程 for (int i = 0; i < 5; i++) { pthread_create(&readers[i], NULL, th_read, NULL); } // 等待所有线程结束(实际上不会结束,因为线程是无限循环) for (int i = 0; i < 3; i++) { pthread_join(writers[i], NULL); } for (int i = 0; i < 5; i++) { pthread_join(readers[i], NULL); } pthread_rwlock_destroy(&rwlock); // 销毁读写锁 return 0; } ``` 在这个示例中,`th_write` 函数负责写入操作,它会在每次写入前获取写锁,并在写入后释放写锁。而 `th_read` 函数负责读取操作,它会在每次读取前获取读锁,并在读取后释放读锁。这样可以确保在写入时不会有其他线程读取或写入,而在读取时允许多个线程同时读取[^4]。 ### 注意事项 - **避免死锁**:确保在加锁和解锁之间不要有异常退出的情况,否则可能导致死锁。 - **性能优化**:读写锁适用于读多写少的场景。如果写操作频繁,读写锁可能不如互斥锁(`pthread_mutex_t`)高效。 - **锁的公平性**:读写锁的实现可能不会保证等待时间最长的线程优先获得锁,因此在某些情况下可能会出现饥饿现象。 ###
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值