十五、互斥锁、原子操作、死锁和读写锁

1、互斥锁

1.1 互斥锁类型

  创建一把锁: pthread_mutex_t mutex;

1.2互斥锁的特点:

  多个线程访问共享数据的时候是串行的

1.3 使用互斥锁缺点

  效率低

1.4 互斥锁使用的步骤

  创建互斥锁: pthread_mutex_t mutex;

  初始化:pthread_mutex_init(&mutex,NULL); -- mutex = 1

  找到线程共同操作的共享数据

                       加锁:操作共享资源之前加锁,pthread_mutex_lock(&mutex); //阻塞 --mutex = 0

                        pthread_mutex_trylock(&mutex); // 如果锁上锁直接返回,不阻塞

                                    XXXXXX共享数据操作 //临界区 ,越小越好

                       解锁:pthread_mutex_unlock(&mutex); // -- mutex = 1

                                    阻塞在锁上的线程会被唤醒

   销毁:pthread_mutex_destory(&mutex);

1.5 互斥锁相关函数

  初始化互斥锁

  pthread_mutex_init(

  pthread_mutex_t* restrict mutex,

  const pthread_mutexattr_t* restrict attr,

  );

  销毁互斥锁:

  pthread_mutex_destory(pthread_mutex_t* mutex );

  加锁

  pthread_mutex_lock(pthread_mutex* mutex);

  mutex:

      没有被锁上,当前线程会将这把锁锁上

      被锁上了:当前线程阻塞,锁被打开之后,线程解除阻塞

          尝试加锁,失败返回,不阻塞

   pthread_mutex_trylock(pthread_mutex_t* mutex);

  没有锁上:当前线程会被这把锁加锁

  如果锁上了:不会阻塞,返回

  返回0:加锁 成功。没锁上:返回错误号

if( pthread_mutex_trylock(& mutex)==0)
{
//尝试加锁,并且成功了
//访问共享资源
XXXXXXXX
}
else
{
//错误处理
//或者等待,再次尝试加锁
}
  解锁
  pthread_mutex_unlock(pthread_mutex_t* mutex)

2、原子操作

CPU处理一个指令,进程/线程 在处理完这个指令之前是不会失去CPU的
就像原子被认为是不可分割颗粒一样。
//示例代码1:
void* procucer(void * arg)
{
while(1)
{
//创建一个链表的节点
Node * newNode = (Node*)malloc(sizeof(Node));
//init
newNode‐>data = rang()%100;
newNode ‐>next = head;
head = newNode;
printf("+++product:%d\n",newNode‐>data);
sleep(rang()%3);
}
reutn NULL;
}
//示例代码2:
void* procucer(void * arg)
{
while(1)
{
//创建一个链表的节点
Node * newNode = (Node*)malloc(sizeof(Node));
//init
newNode‐>data = rang()%100;
pthread_mutex_lock(&mutex);
newNode ‐>next = head;
head = newNode;
printf("+++product:%d\n",newNode‐>data);
pthread_mutex_unlock(&mutex);
sleep(rang()%3);
}
reutn NULL;
}

3、死锁

1.自己锁自己:

for(int i = 0;i<MAX;i++)
{
pthread_mutex_lock(&mutex);
pthread_mutex_lock(&mutex);
int crt = number;
crt++;
number = crt;
printf("thread A id = %ld,number = %d\n",pthread_self(),number);
pthread_mutex_unlock(&mutex);
usleep(10);
}
//操作做完之后,一定要解锁

2.

  线程1 对共享资源A加锁成功-A锁

  线程2 对共享资源B加锁成功-B锁

  线程1访问共享资源B,对B锁加锁-线程1阻塞在B锁上

  线程2访问共享资源A,对A锁加锁-线程2阻塞在A锁上

  如何解决: 让线程按照一定的顺序去访问共享资源-在访问其他锁的时候,需要先将自己的锁解开 --try_lock

4、读写锁

4.1. 读写锁是几把锁

  一把锁

  pthread_rwlock_t lock;

4.2. 读写锁的类型

  读锁-对内存做读操作

  写锁-对内存做写操作

4.3读写锁的特性:

  线程A加读锁成功,又来了三个线程,做读操作,可以加锁成功

          读共享-并行处理

  线程A加写锁成功,又来了三个线程,做读操作,三个线程阻塞

           写独占

  线程A加读锁成功,又来了B线程加写锁阻塞,又来了C线程加读锁阻塞

           读写不可以同时进行

  写的优先级高

4.4. 读写锁场景练习

  线程A加写锁成功,线程B请求读锁

          线程B阻塞

  线程A持有读锁,线程B请求写锁

         线程B阻塞

  线程A拥有读写,线程B请求读锁

         线程B加锁

  线程A持有读锁,然后线程B请求写锁,然后线程C请求读锁

        线程B阻塞,线程C阻塞

        线程B加锁,线程C阻塞

        线程C加锁

线程A持有写锁,然后线程B请求读锁,然后线程C请求写锁

       线程B阻塞,线程C阻塞

       线程C加锁, 线程B阻塞

       线程B加锁

4.5.读写锁的适用场景

  互斥锁-读写串行

  读写锁:

  读:并行

  写:串行

  程序中的读操作 > 写操作的时候

4.6. 主要操作函数

  初始化读写锁

  pthread_rwlock_init(pthread_rwlock_t* restrict rwlock,

  const pthread_rwlockattr_t* restrict attr );

  销毁读写锁

  pthread_rwlock_destroy(pthread_rwlock_t* rwlock):

  加读锁

  pthread_rwlock_rdlock(pthread_rwlock_t* rdlock);

  阻塞:之前对这把锁加的是写锁的操作

  尝试加读锁

  pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock);

  加锁成功:返回0

  失败:返回错误号

  加写锁

  pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);

  阻塞:上一次加写锁还没解锁

  阻塞:上一次加读锁还没解锁

  尝试加写锁

  pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock);

  解锁

  pthread_rwlock_unlock(pthread_rwlock_t* rwlock)

4.7. 练习

三个线程不定时写同一个全局变量,五个线程不定时期读同一全局资源
示例代码:
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
int number=10000;
//lock
pthread_rwlock_t lock;
void * fun_read(void *arg)
{
	while(1)
	{
		pthread_rwlock_rdlock(&lock);
		number++;
		printf("read:%ld number is %d\n",pthread_self(),number);
		pthread_rwlock_unlock(&lock);
		usleep(500);
	}
}
void * fun_write(void *arg)
{
        while(1)
        {
                pthread_rwlock_wrlock(&lock);
                printf("write:%ld number is %d\n",pthread_self(),number);
		pthread_rwlock_unlock(&lock);
                usleep(500);
        }
}

int main()
{
	pthread_rwlock_init(&lock,NULL);
	pthread_t a[8];
	int i=0;
	for(i=0;i<3;i++)
	{
		pthread_create(&a[i],NULL,fun_read,NULL);
	}
	for(i=3;i<8;i++)
	{
		pthread_create(&a[i],NULL,fun_write,NULL);
	}
	for(i=0;i<8;i++)
	{
		pthread_join(a[i],NULL);
	}
	pthread_rwlock_destroy(&lock);

	return 0;
}

  运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值