Linux 线程 —— 锁相关

目录

1. 互斥量(互斥锁)

1.1 互斥锁类型:

1.2 互斥锁的特点:

1.3 使用互斥锁缺点:

1.4 互斥锁使用的步骤:

1.5 互斥锁相关函数

1.6 互斥锁代码案例 pthread_mutex.c

2. 读写锁

2.1 读写锁概念:

2.2 读写锁的类型

2.3 读写锁的特性

 2.4 读写锁场景练习

 2.5 读写锁的适用场景

 2.6 主要操作函数

 2.7 练习

2.7.1 代码 pthread_rwlock.c


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);

没有被锁上:当前线程会将这把锁锁上。被锁上了:当前线程阻塞,
锁被打开之后,线程解除阻塞。尝试加锁,失败返回,不阻塞

pthread_mutex_trylock(pthread_mutex_t* mutex);
没有锁上:当前线程会被这把锁加锁
如果锁上了:不会阻塞,返回
返回0:加锁 成功。没锁上:返回错误号

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

1.6 互斥锁代码案例 pthread_mutex.c

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

#define MAX 10000
int number; // 全局变量默认初始化为0
// create mutex
pthread_mutex_t mutex;

// 线程 A 处理函数
void *funA(void *arg)
{
	for (int i = 0; i < MAX; i++)
	{
		// Lock
		pthread_mutex_lock(&mutex);

		number++;
		int ret = number;
		printf("funA id = %ld, A_number = %d\n", pthread_self(), number);

		// Unlock
		pthread_mutex_unlock(&mutex);
		usleep(10);
	}
}

// 线程 B 处理函数
void *funB(void *arg)
{
	for (int i = 0; i < MAX; i++)
	{
		// Lock
		pthread_mutex_lock(&mutex);

		number++;
		int ret = number;
		printf("funB id = %ld, B_number = %d\n", pthread_self(), number);

		// Unlock
		pthread_mutex_unlock(&mutex);
		usleep(10);
	}
}

int main()
{
	// Init mutex
	pthread_mutex_init(&mutex, NULL); // 创建互斥锁
	pthread_t pth1, pth2;

	// 创建线程
	pthread_create(&pth1, NULL, funA, NULL);
	pthread_create(&pth2, NULL, funB, NULL);

	// 等待线程结束
	pthread_join(pth1, NULL);
	pthread_join(pth2, NULL);

	// 销毁互斥锁
	pthread_mutex_destroy(&mutex);

	return 0;
}

2. 读写锁

2.1 读写锁概念:

  • 读写锁是一把锁,而不是两把
  • pthread_rwlock_t lock;

2.2 读写锁的类型

  • 读锁-对内存做读操作
  • 写锁-对内存做写操作

2.3 读写锁的特性

 2.4 读写锁场景练习

 2.5 读写锁的适用场景

 2.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)

 2.7 练习

三个线程不定时写同一个全局变量,五个线程不定时期读同一全局资源

2.7.1 代码 pthread_rwlock.c

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

int number;
// create rwlock
pthread_rwlock_t lock;

void *write_func(void *arg)
{
	while (number < 5000)
	{
		pthread_rwlock_wrlock(&lock); // 加写锁
		number++;
		printf("write: %ld, %d\n", pthread_self(), number);
		pthread_rwlock_unlock(&lock); // 解写锁
		usleep(500);
	}
}

void *read_func(void *arg)
{
	while (number < 5000)
	{
		pthread_rwlock_rdlock(&lock); // 加读锁
		printf("read: %ld, %d\n", pthread_self(), number);
		pthread_rwlock_unlock(&lock); // 解读锁
		usleep(500);
	}
}

int main()
{
	pthread_rwlock_init(&lock, NULL);
	pthread_t p[8];

	// 前三个线程是写线程
	for (int i = 0; i < 3; i++)
	{
		pthread_create(&p[i], NULL, write_func, NULL);
	}

	// 后五个线程是读线程
	for (int i = 3; i < 8; i++)
	{
		pthread_create(&p[i], NULL, read_func, NULL);
	}

	// 等待八个线程结束
	for (int i = 0; i < 8; i++)
	{
		pthread_join(p[i], NULL);
	}

	// 销毁读写锁
	pthread_rwlock_destroy(&lock);
	return 0;
}

运行结果:

 写操作的时候只能一个线程操作,但是读操作的时候可以多个线程同时读取共享资源,读出的值是同一个,比互斥锁效率更高。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux中的多线程实际上是通过进程来模拟实现的。在Linux中,多个线程是通过共享父进程的资源来实现的,而不是像其他操作系统那样拥有自己独立的线程管理模块。因此,在Linux中所谓的“线程”其实是通过克隆父进程的资源而形成的“线程”。这也是为什么在Linux中所说的“线程”概念需要加上引号的原因。 对于Linux中的线程,需要使用线程库来进行管理。具体来说,Linux中的线程ID(pthread_t类型)实质上是进程地址空间上的一个地址。因此,要管理这些线程,需要在线程库中进行描述和组织。 由于Linux中没有真正意义上的线程,因此线程的管理和调度都是由线程库来完成的。线程库负责创建线程、终止线程、调度线程、切换线程,以及为线程分配资源、释放资源和回收资源等任务。需要注意的是,线程的具体实现取决于Linux的实现,目前Linux使用的是NPTL(Native POSIX Thread Library)。 总结来说,Linux中的多线程是通过进程来模拟实现的,线程共享父进程的资源。线程的管理和调度由线程库完成。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Linux —— 多线程](https://blog.csdn.net/sjsjnsjnn/article/details/126062127)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值