Linux互斥量读写锁
一、互斥量
1.临界资源
同一时刻只允许一个进程/线程访问的共享资源(比如文件、外设打印机)
2.临界区
访问临界资源的代码
3.互斥机制
mutex互斥锁,用来避免临界资源的访问冲突,访问临界资源前申请互斥锁,访问完释放锁
形象点的说法 好比有一个公共卫生间,进去使用的人会给门上锁,使用完会开锁
4.创建互斥锁
/*动态创建*/
pthread_mutex_t mutex
pthread_mutex_t_init(pthread_mutex_t *mutex,互斥锁属性 给NULL默认即可)
/*静态创建*/
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
5.销毁互斥锁
pthread_mutex_destory(pthread_mutex_t *mutex)
Linux中,互斥锁不占任何资源,所以销毁锁不是必须的,可利用其返回值查询锁状态,锁定时返回EBUSY
6.申请互斥锁(P操作)
pthread_mutex_lock(pthread_mutex_t *mutex) //无锁时阻塞等待
pthread_mutex_trylock(pthread_mutex_t *mutex) //无锁返回EBUSY
7.释放互斥锁(V操作)
pthread_mutex_unlock(pthread_mutex_t *mutex)
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
FILE *fp;
void *func2(void *arg){
pthread_detach(pthread_self());
printf("This func2 thread\n");
char str[]="I write func2 line\n";
char c;
int i=0;
while(1){
pthread_mutex_lock(&mutex);
while(i<strlen(str))
{
c = str[i];
fputc(c,fp);
usleep(1);
i++;
}
pthread_mutex_unlock(&mutex);
i=0;
usleep(1);
}
pthread_exit("func2 exit");
}
void *func(void *arg){
pthread_detach(pthread_self());
printf("This is func1 thread\n");
char str[]="You read func1 thread\n";
char c;
int i=0;
while(1){
pthread_mutex_lock(&mutex);
while(i<strlen(str))
{
c = str[i];
fputc(c,fp);
i++;
usleep(1);
}
pthread_mutex_unlock(&mutex);
i=0;
usleep(1);
}
pthread_exit("func1 exit");
}
int main(){
pthread_t tid,tid2;
void *retv;
int i;
fp = fopen("1.txt","a+");
if(fp==NULL){
perror("fopen");
return 0;
}
pthread_create(&tid,NULL,func,NULL);
pthread_create(&tid2,NULL,func2,NULL);
while(1){
sleep(1);
}
}
二、读写锁
与互斥锁的区别是:
-
互斥锁对所有线程一视同仁,同一时刻只允许一个线程访问临界资源
-
读写锁区分读者和写者,同一时刻只允许一个写者访问临界资源,而读者允许多个同时访问,更具体地:
-
写锁状态时,其他写锁、读锁都被阻塞;
-
读锁状态时,读锁不阻塞,写锁阻塞,但在写锁阻塞之后申请的读锁要阻塞等待写锁(否则重要的内容一直写不进去)
-
pthread_rwlock_t rwlock //定义读写锁
/*申请写锁*/
pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
/*申请读锁*/
pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
/*释放锁*/
pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
/*销毁读写锁*/
pthread_rwlock_destory(pthread_rwlock_t *rwlock)
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
pthread_rwlock_t rwlock;
FILE *fp;
void * read_func(void *arg){
pthread_detach(pthread_self());
printf("read thread\n");
char buf[32]={0};
while(1){
//rewind(fp);
pthread_rwlock_rdlock(&rwlock);
while(fgets(buf,32,fp)!=NULL){
printf("%d,rd=%s\n",(int)arg,buf);
usleep(1000);
}
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
}
void *func2(void *arg){
pthread_detach(pthread_self());
printf("This func2 thread\n");
char str[]="I write func2 line\n";
char c;
int i=0;
while(1){
pthread_rwlock_wrlock(&rwlock);
while(i<strlen(str))
{
c = str[i];
fputc(c,fp);
usleep(1);
i++;
}
pthread_rwlock_unlock(&rwlock);
i=0;
usleep(1);
}
pthread_exit("func2 exit");
}
void *func(void *arg){
pthread_detach(pthread_self());
printf("This is func1 thread\n");
char str[]="You read func1 thread\n";
char c;
int i=0;
while(1){
pthread_rwlock_wrlock(&rwlock);
while(i<strlen(str))
{
c = str[i];
fputc(c,fp);
i++;
usleep(1);
}
pthread_rwlock_unlock(&rwlock);
i=0;
usleep(1);
}
pthread_exit("func1 exit");
}
int main(){
pthread_t tid1,tid2,tid3,tid4;
void *retv;
int i;
fp = fopen("1.txt","a+");
if(fp==NULL){
perror("fopen");
return 0;
}
pthread_rwlock_init(&rwlock,NULL);
pthread_create(&tid1,NULL,read_func,1);
pthread_create(&tid2,NULL,read_func,2);
pthread_create(&tid3,NULL,func,NULL);
pthread_create(&tid4,NULL,func2,NULL);
while(1){
sleep(1);
}
}
死锁的避免
概念:有两把锁以上时,多个线程各自申请到锁时,紧接着申请其他线程占用着的锁,它们都会处于阻塞等待,形成【死锁】
避免方法:
-
锁越少越好,一把锁无需考虑死锁问题
-
调整锁的顺序
-
一种笨策略是,某个线程如果想要申请多个锁,那么可以等其释放完,其他线程再申请
-
另一种笨策略是,各个线程按同样的顺序申请多个锁
-