首页 > 系统相关 >linux9 互斥锁 死锁 读写锁 条件变量 信号量

linux9 互斥锁 死锁 读写锁 条件变量 信号量

时间:2023-07-20 14:57:53浏览次数:42  
标签:rwlock linux9 互斥 死锁 mutex pthread sem NULL

1.linux 9day

1.线程竞争

![01-打印机模型](I:\9 day\01-打印机模型.png)

2.同步和互斥

互斥
同一时刻只能一个进程或线程使用 多个进程或线程不能同时使用

同步:是指散步在不同任务之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。最基本的场景就是:两个或两个以上的进程或线程在运行过程中协同步调,按预定的先后次序运行。比如 A 任务的运行依赖于 B 任务产生的数据。

生产者消费者

显然,同步是一种更为复杂的互斥,而互斥是一种特殊的同步。

互斥:无次序
同步:有次序

3.互斥锁函数介绍

1.互斥锁介绍

而在线程里也有这么一把锁:互斥锁(mutex),也叫互斥量,互斥锁是一种简单的加锁的方法来控制对共享资源的访问,互斥锁只有两种状态,即加锁( lock )和解锁( unlock )。

1)在访问共享资源后临界区域前,对互斥锁进行加锁。

2)在访问完成后释放互斥锁导上的锁。

3)对互斥锁进行加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁被释放。

互斥锁的数据类型是: pthread_mutex_t。

2.初始化互斥锁 pthread_mutex_init

初始化互斥锁:

#include <pthread.h>

int pthread_mutex_init(pthread_mutex_t *restrict mutex,
    const pthread_mutexattr_t *restrict attr);
功能:
    初始化一个互斥锁。
参数:
    mutex:互斥锁地址。类型是 pthread_mutex_t 。
    attr:设置互斥量的属性,通常可采用默认属性,即可将 attr 设为 NULL。

    可以使用宏 PTHREAD_MUTEX_INITIALIZER 静态初始化互斥锁,比如:
    pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;

这种方法等价于使用 NULL 指定的 attr 参数调用 pthread_mutex_init() 来完成动态初始化,不同之处在于 PTHREAD_MUTEX_INITIALIZER 宏不进行错误检查。

返回值:
    成功:0,成功申请的锁默认是打开的。
    失败:非 0 错误码

restrict,C语言中的一种类型限定符(Type Qualifiers),用于告诉编译器,对象已经被指针所引用,不能通过除该指针外所有其他直接或间接的方式修改该对象的内容。

3.互斥锁销毁 pthread_mutex_destroy
#include <pthread.h>

int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:
    销毁指定的一个互斥锁。互斥锁在使用完毕后,必须要对互斥锁进行销毁,以释放资源。
参数:
    mutex:互斥锁地址。
返回值:
    成功:0
    失败:非 0 错误码

4.上锁函数 pthread_mutex_lock

#include <pthread.h>

int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:
    对互斥锁上锁,若互斥锁已经上锁,则调用者阻塞,直到互斥锁解锁后再上锁。
参数:
    mutex:互斥锁地址。
返回值:
    成功:0
    失败:非 0 错误码

int pthread_mutex_trylock(pthread_mutex_t *mutex);
   调用该函数时,若互斥锁未加锁,则上锁,返回 0;
   若互斥锁已加锁,则函数直接返回失败,即 EBUSY。

4.互斥锁解锁 pthread_mutex_unlock
#include <pthread.h>

int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:
    对指定的互斥锁解锁。
参数:
    mutex:互斥锁地址。
返回值:
    成功:0
    失败:非0错误码

5.互斥锁案例

对一变量写入 理想20w ->但会被写入覆盖导致数据丢失 故此加锁

int ic = 0;
pthread_mutex_t mutex;//互斥锁
void* thread_fun1(void* arg)
{
	for (int i = 0; i < 100000; i ++ )
	{
pthread_mutex_lock(&mutex);//加锁
		ic++;
pthread_mutex_unlock(&mutex);//解锁
	}
	
}
void* thread_fun2(void* arg)
{
	for (int i = 0; i < 100000; i++)
	{
		pthread_mutex_lock(&mutex);//加锁
		ic++;
pthread_mutex_unlock(&mutex);//解锁
	}
}

int main(void)
{
	pthread_t tid1;
	pthread_t tid2;
	int ret = -1;

ret=pthread_mutex_init(&mutex,NULL);///创建锁

	ret = pthread_create(&tid1, NULL, thread_fun1, NULL);
	ret = pthread_create(&tid2, NULL, thread_fun2, NULL);

	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
    //创建线程完 等待线程跑完
pthread_mutex_destroy(&mutex);
	printf("全局变量%d\n", ic);
}

4.死锁 互斥锁概念

什么是死锁

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

死锁原因

![04-死锁](I:\9 day\04-死锁.png)

竞争不可抢占资源引起死锁

竞争可消耗资源引起死锁

进程推进顺序不当引起死锁

死锁的必要条件

竞争资源,另一方需要等待资源

处理死锁

破坏死锁的循环

死锁代码演示

![死锁](I:\9 day\死锁.png)

5.读写锁

![06-读写锁](I:\9 day\06-读写锁.png)

在对数据的读写操作中,更多的是读操作,写操作较少,例如对数据库数据的读写应用。为了满足当前能够允许多个读出,但只允许一个写入的需求,线程提供了读写锁来实现。

1.读写锁特点

1)如果有其它线程读数据,则允许其它线程执行读操作,但不允许写操作。

2)如果有其它线程写数据,则其它线程都不允许读、写操作。

读写锁分为读锁和写锁,规则如下:

1)如果某线程申请了读锁,其它线程可以再申请读锁,但不能申请写锁。

2)如果某线程申请了写锁,其它线程不能申请读锁,也不能申请写锁。

POSIX 定义的读写锁的数据类型是: pthread_rwlock_t。

2.读写锁函数
1.初始化读写锁 pthread_rwlock_init
#include <pthread.h>

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
    const pthread_rwlockattr_t *restrict attr);
功能:
    用来初始化 rwlock 所指向的读写锁。

参数:
    rwlock:指向要初始化的读写锁指针。
    attr:读写锁的属性指针。如果 attr 为 NULL 则会使用默认的属性初始化读写锁,否则使用指定的 attr 初始化读写锁。

    可以使用宏 PTHREAD_RWLOCK_INITIALIZER 静态初始化读写锁,比如:
    pthread_rwlock_t my_rwlock = PTHREAD_RWLOCK_INITIALIZER;

    这种方法等价于使用 NULL 指定的 attr 参数调用 pthread_rwlock_init() 来完成动态初始化,不同之处在于PTHREAD_RWLOCK_INITIALIZER 宏不进行错误检查。

返回值:
    成功:0,读写锁的状态将成为已初始化和已解锁。
    失败:非 0 错误码。

2.销毁读写锁 pthread_rwlock_destroy
#include <pthread.h>

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
功能:
    用于销毁一个读写锁,并释放所有相关联的资源(所谓的所有指的是由 pthread_rwlock_init() 自动申请的资源) 。
参数:
    rwlock:读写锁指针。
返回值:
    成功:0
    失败:非 0 错误码

3.加读锁 pthread_rwlock_rdlock
#include <pthread.h>

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
功能:
    以阻塞方式在读写锁上获取读锁(读锁定)。
    如果没有写者持有该锁,并且没有写者阻塞在该锁上,则调用线程会获取读锁。
    如果调用线程未获取读锁,则它将阻塞直到它获取了该锁。一个线程可以在一个读写锁上多次执行读锁定。
    线程可以成功调用 pthread_rwlock_rdlock() 函数 n 次,但是之后该线程必须调用 pthread_rwlock_unlock() 函数 n 次才能解除锁定。
参数:
    rwlock:读写锁指针。
返回值:
    成功:0
    失败:非 0 错误码

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
   用于尝试以非阻塞的方式来在读写锁上获取读锁。
   如果有任何的写者持有该锁或有写者阻塞在该读写锁上,则立即失败返回。

4.加写锁 pthread_rwlock_wrlock
#include <pthread.h>

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
功能:
    在读写锁上获取写锁(写锁定)。
    如果没有写者持有该锁,并且没有写者读者持有该锁,则调用线程会获取写锁。
    如果调用线程未获取写锁,则它将阻塞直到它获取了该锁。
参数:
    rwlock:读写锁指针。
返回值:
    成功:0
    失败:非 0 错误码

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
   用于尝试以非阻塞的方式来在读写锁上获取写锁。
   如果有任何的读者或写者持有该锁,则立即失败返回。

4.解锁 pthread_rwlock_unlock
#include <pthread.h>

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
功能:
    无论是读锁或写锁,都可以通过此函数解锁。
参数:
    rwlock:读写锁指针。
返回值:
    成功:0
    失败:非 0 错误码

5.读写锁示例

读写案例

//写fifo1 读fifo2
int ic = 0;
pthread_rwlock_t rwlock;

void* fun_read(void* arg)
{
while(1)
{
	//读取ic值
	int index = 0;
sleep(1);
	pthread_rwlock_rdlock(&rwlock);
	printf("线程%d 读取num的值%d \n", index, ic);
	
	//解锁
	pthread_rwlock_unlock(&rwlock);
}
}
void* fun_write(void* arg)
{
	//读取ic值
	int index = 1;
while(1)
{	
pthread_rwlock_wrlock(&rwlock);
	ic++;
	printf("线程%d 写num的值%d \n", index, ic);
	sleep(1);
	//解锁
	pthread_rwlock_unlock(&rwlock);
}
}
int main(void)
{
	pthread_t tid[8];
	int i = 0;
	int ret = -1;
	//初始化读锁
	ret = pthread_rwlock_init(&rwlock, NULL);

	for (i = 0; i < 8; i++)
	{
		if (i < 5)
		{
			pthread_create(&tid[i], NULL, fun_read, NULL);

		}
		else
		{
			pthread_create(&tid[i], NULL, fun_write,NULL);
		}

	}

	//回收资源
	for (i = 0; i < 8; i++)
	{
		pthread_join(tid[i], NULL);
	}
return 0;
}



创建八个线程 5读 3写

6.条件变量控制

1.条件变量概念

与互斥锁不同,条件变量是用来等待而不是用来上锁的,条件变量本身不是锁

条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。

条件变量的两个动作:

  • 条件不满, 阻塞线程
  • 当条件满足, 通知阻塞的线程开始工作

条件变量的类型: pthread_cond_t。

2.条件变量函数

1.初始化条件变量

#include <pthread.h>

int pthread_cond_init(pthread_cond_t *restrict cond,
    const pthread_condattr_t *restrict attr);
功能:
    初始化一个条件变量
参数:
    cond:指向要初始化的条件变量指针。
    attr:条件变量属性,通常为默认值,传NULL即可
        也可以使用静态初始化的方法,初始化条件变量:
        pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
返回值:
    成功:0
    失败:非0错误号

2.销毁条件变量

#include <pthread.h>

int pthread_cond_destroy(pthread_cond_t *cond);
功能:
    销毁一个条件变量
参数:
    cond:指向要初始化的条件变量指针
返回值:
    成功:0
    失败:非0错误号

3.阻塞等待条件变量

#include <pthread.h>

int pthread_cond_wait(pthread_cond_t *restrict cond,
    pthread_mutex_t *restrict mutex);
功能:
    阻塞等待一个条件变量
    a) 阻塞等待条件变量cond(参1)满足
    b) 释放已掌握的互斥锁(解锁互斥量)相当于pthread_mutex_unlock(&mutex);
            a) b) 两步为一个原子操作。
    c) 当被唤醒,pthread_cond_wait函数返回时,解除阻塞并重新申请获取互斥锁pthread_mutex_lock(&mutex);

参数:
    cond:指向要初始化的条件变量指针
    mutex:互斥锁

返回值:
    成功:0
    失败:非0错误号

int pthread_cond_timedwait(pthread_cond_t *restrict cond,
    pthread_mutex_t *restrict mutex,
    const struct
                           .*restrict abstime);
功能:
    限时等待一个条件变量

参数:
    cond:指向要初始化的条件变量指针
    mutex:互斥锁
    abstime:绝对时间

返回值:
    成功:0
    失败:非0错误号

abstime补充说明:

struct timespec {
    time_t tv_sec;      /* seconds */ // 秒
    long   tv_nsec; /* nanosecondes*/ // 纳秒
}

time_t cur = time(NULL);        //获取当前时间。
struct timespec t;              //定义timespec 结构体变量t
t.tv_sec = cur + 1;             // 定时1秒
pthread_cond_timedwait(&cond, &t);

4.唤醒条件变量线程

#include <pthread.h>

int pthread_cond_signal(pthread_cond_t *cond);
功能:
    唤醒至少一个阻塞在条件变量上的线程
参数:
    cond:指向要初始化的条件变量指针
返回值:
    成功:0
    失败:非0错误号

int pthread_cond_broadcast(pthread_cond_t *cond);
功能:
    唤醒全部阻塞在条件变量上的线程
参数:
    cond:指向要初始化的条件变量指针
返回值:
    成功:0
    失败:非0错误号

条件变量示例
#define SIZE 128
int ic = 0; 
pthread_cond_t cond;
pthread_mutex_t mutex;
void* thread_fun1(void* arg)
{
	while (1)
	{
		pthread_mutex_lock(&mutex);
		ic = 1;
		pthread_mutex_unlock(&mutex);
		printf("条件已经改变\n");
		//唤醒因为条件阻塞的线程
		pthread_cond_signal(&cond);
		sleep(2);
	}
	
}
void* thread_fun2(void* arg)
{
	while (1)
	{

		pthread_mutex_lock(&mutex);
		if (0 == ic)
		{
			//等待条件 
			pthread_cond_wait(&cond, &mutex);
            //如果cpu先划分线程2 这个等待条件内部会自动解锁一次
            //带函数退出再加锁
		}
		
		
		printf("线程2执行\n");
		//唤醒因为条件阻塞的线程
		ic = 0;
		pthread_mutex_unlock(&mutex);

		sleep(2);

}
}

int main(void)
{
	pthread_t tid1;
	pthread_t tid2;
	int ret = -1;
	//初始化锁
	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&cond, NULL);

	ret = pthread_create(&tid1, NULL, thread_fun1, NULL);
	ret = pthread_create(&tid2, NULL, thread_fun2, NULL);

	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);

}

生产者消费者模型

ps:两个线程 一个模拟生产者行为 一个模拟消费者行为 两个线程同时操作一个共享资源,生产向其中添加产品,消费者从中消费掉产品

![生产者消费者模型](I:\9 day\生产者消费者模型.jpeg)

int ic = 0; 
pthread_cond_t cond;
pthread_mutex_t mutex;
// 永远指向链表头部的指针


typedef struct node

{
	int data;
	struct node* next;

}node_t;
node_t* head = NULL;
//生产者
void* thread_fun1(void* arg)
{
	while (1)
	{
		node_t* new = malloc(sizeof(node_t));
		if (NULL == new)
		{
			printf("malloc");
			break;
		}
		memset(new, 0, sizeof(node_t));
		pthread_mutex_lock(&mutex);
		new->data = rand() % 100 + 1;
		new->next = NULL;
		//头插法
		new->next = head;
		head = new;
		pthread_mutex_unlock(&mutex);//解锁
        pthread_cond_signal(&cond);//通知消费者线程
		sleep(rand() % 3);
	}
	return NULL;
}
//消费者

void* thread_fun2(void* arg)
{
	while (1)
	{
		pthread_mutex_lock(&mutex);
		if (head = NULL);
		{
			//阻塞
			pthread_cond_wait(&cond, &mutex);
		}
	//删除节点
		node_t* pdel = head;
		head = head->next;

		printf("数据去吃 % d\n", pdel->data);
		free(pdel);
		pthread_mutex_unlock(&mutex);
}       
}

int main(void)
{
	pthread_t tid1;
	pthread_t tid2;
	int ret = -1;
	//初始化锁
	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&cond, NULL);

	ret = pthread_create(&tid1, NULL, thread_fun1, NULL);
	ret = pthread_create(&tid2, NULL, thread_fun2, NULL);

	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);

}

7.信号量

1.信号量概述

信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。

​ 编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值大于 0 时,则可以访问,否则将阻塞。

​ PV 原语是对信号量的操作,一次 P 操作使信号量减1,一次 V 操作使信号量加1。

​ 信号量数据类型为:sem_t。

信号量用于互斥:

![信号量互斥](I:\9 day\信号量互斥.png)

信号量同步
![信号量同步](I:\9 day\信号量同步.png)

2.信号量函数

1.初始化信号量:

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:
    创建一个信号量并初始化它的值。一个无名信号量在被使用前必须先初始化。
参数:
    sem:信号量的地址。
    pshared:等于 0,信号量在线程间共享(常用);不等于0,信号量在进程间共享。
    value:信号量的初始值。
返回值:
    成功:0
    失败: - 1

2.销毁信号量:

#include <semaphore.h>

int sem_destroy(sem_t *sem);
功能:
    删除 sem 标识的信号量。
参数:
    sem:信号量地址。
返回值:
    成功:0
    失败: - 1


3.信号量p操作

#include <semaphore.h>

int sem_wait(sem_t *sem);
功能:
    将信号量的值减 1。操作前,先检查信号量(sem)的值是否为 0,若信号量为 0,此函数会阻塞,直到信号量大于 0 时才进行减 1 操作。
参数:
    sem:信号量的地址。
返回值:
    成功:0
    失败: - 1

int sem_trywait(sem_t *sem);
   以非阻塞的方式来对信号量进行减 1 操作。
   若操作前,信号量的值等于 0,则对信号量的操作失败,函数立即返回。

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
   限时尝试将信号量的值减 1
   abs_timeout:绝对时间

abs_timeout补充说明:

struct timespec {
    time_t tv_sec;      /* seconds */ // 秒
    long   tv_nsec; /* nanosecondes*/ // 纳秒
}

time_t cur = time(NULL);        //获取当前时间。
struct timespec t;              //定义timespec 结构体变量t
t.tv_sec = cur + 1;             // 定时1秒
sem_timedwait(&cond, &t);

4.信号量v操作

#include <semaphore.h>

int sem_post(sem_t *sem);
功能:
    将信号量的值加 1 并发出信号唤醒等待线程(sem_wait())。
参数:
    sem:信号量的地址。
返回值:
    成功:0
    失败:-1

5.信号量获取

#include <semaphore.h>

int sem_getvalue(sem_t *sem, int *sval);
功能:
    获取 sem 标识的信号量的值,保存在 sval 中。
参数:
    sem:信号量地址。
    sval:保存信号量值的地址。
返回值:
    成功:0
    失败:-1

信号量案例

sem_t sem; //信号量
void printer(char *str)
{
    sem_wait(&sem);//减一
    while (*str)
    {
        putchar(*str);
        fflush(stdout);
        str++;
        sleep(1);
    }
    printf("\n");
    sem_post(&sem);//加一
}
void *thread_fun1(void *arg)
{
    char *str1 = "hello";
    printer(str1);
}
void *thread_fun2(void *arg)
{
    char *str2 = "world";
    printer(str2);
}
int main(void)
{
    pthread_t tid1, tid2;

    sem_init(&sem, 0, 1); //初始化信号量,初始值为 1

    //创建 2 个线程
    pthread_create(&tid1, NULL, thread_fun1, NULL);
    pthread_create(&tid2, NULL, thread_fun2, NULL);
    //等待线程结束,回收其资源
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    sem_destroy(&sem); //销毁信号量
    return 0;
}
 
1.信号量的生产者消费者模型
#define SIZE 128
int ic = 0; 
sem_t sem_producer;//容器量
sem_t semmsl;//可以卖的数量
// 永远指向链表头部的指针


typedef struct node

{
	int data;
	struct node* next;

}node_t;
node_t* head = NULL;
//生产者
void* thread_fun1(void* arg)
{
	while (1)
	{
		//申请1个容器 sem_wait
		sem_wait(&sem_producer);
		node_t* new = malloc(sizeof(node_t));
		if (NULL == new)
		{
			printf("malloc");
			break;
		}
		memset(new, 0, sizeof(node_t));
	
		new->data = rand() % 100 + 1;
		new->next = NULL;
		//头插法
		new->next = head;
		head = new;
		sem_post(&semmsl);//通知消费 
		sleep(rand() % 3);
	}
	return NULL;
}
//消费者

void* thread_fun2(void* arg)
{
	while (1)
	{
		sem_wait(&semmsl);//消费
		//删除节点
		node_t* pdel = head;
		head = head->next;

		printf("数据去吃 % d\n", pdel->data);
		free(pdel);
		sem_post(&sem_producer);//容器+1
	}
}

int main(void)
{
	pthread_t tid1;
	pthread_t tid2;
	int ret = -1;
	//容器
	sem_init(&sem_producer, 0, 4);
	//可卖数量
	sem_init(&semmsl, 0, 0);
	ret = pthread_create(&tid1, NULL, thread_fun1, NULL);
	ret = pthread_create(&tid2, NULL, thread_fun2, NULL);

	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);

}




标签:rwlock,linux9,互斥,死锁,mutex,pthread,sem,NULL
From: https://www.cnblogs.com/lzfyz/p/17568398.html

相关文章

  • 手写死锁&&死锁的原因是什么?如何快速定位死锁?如何避免死锁
    一个简单的死锁案例:packagemylock;publicclassDeadlockExample{publicstaticvoidmain(String[]args){finalObjectresource1=newObject();finalObjectresource2=newObject();//线程1占用资源1,等待资源2Threadth......
  • 死锁、活锁
    Java死锁是指两个或多个线程被无限期地阻塞,等待对方释放其持有的资源,导致程序无法继续执行下去的现象。Java死锁通常发生在多个线程之间,其中一个线程持有某个资源,但是同时需要另一个资源,但是该资源被其他线程持有,导致它无法继续执行。为了避免死锁,Java提供了一些机制来避免和解决......
  • 数据库死锁原因以及解决
    有一篇讲了mvcc的基本原理:https://www.cnblogs.com/benjerry/p/17551031.html这样就知道最简单的死锁产生原因,就是有两个并发事务,事务1先更新a表某行数据,再更新b表某行数据,事务2先更新b表同行数据,再更新a表同行数据,就非常有可能死锁了。还有种写法,selectforupdate,将共享锁上升......
  • rtthread_互斥量
    1互斥量  互斥量即互相排斥的信号量,是一种特殊的二值信号量;只能由持有线程释放,而信号量则可以由任何线程释放;  拥有互斥量的线程拥有互斥量的所有权,互斥量支持递归访问且能防止多线程优先级翻转;  1.1线程优先级翻转问题    互斥量通过继承线程优先级,将持有互斥量......
  • Java之多线程的同步和死锁
    设计模式中的单例模式的懒汉方式会存在多线程的安全问题;通过以下测试代码可以看到两个线程中得到的并不是同一个单例对象;@TestpublicvoidunsafeSingleInstanceTest()throwsInterruptedException{AtomicReference<UnSafeSingleInstance>s1=newAtomicRe......
  • 死锁问题定位与分析
    死锁问题定位与分析一.环境搭建1.准备脚本,执行压测2.用jstack打印日志jstack112759>dead.log3.下载日志到本地szdead.log二.问题定位1.打开dead.log搜索deadlock2.查看死锁的线程3.查看死锁位置三.问题分析1.下载死锁的类文件SzCaseController.class2.使用......
  • Rockylinux9或Centos8安装zabbix6.0
    zabbix6.0服务端不再支持Centos7的yum安装,Centos8已停止维护,rockylinux是RHEL的下游免费发行版。1.安装rockylinux9:阿里云下载地址#关闭防火墙和selinux并重启sed-i's/SELINUX=enforcing/SELINUX=disabled/'/etc/selinux/configsystemctldisable--nowfirewalld#查......
  • C++之死锁
    背景在多线程编程中,死锁是一个常见的问题,它会导致程序陷入无法继续执行的状态。在这篇博客中,我们将介绍C++中死锁的概念、产生原因以及解决办法。什么是死锁?死锁是指多个线程在等待对方释放资源,导致彼此都无法继续执行的情况。死锁通常发生在多个线程同时锁定多个互斥锁的情况......
  • GIL锁,互斥锁
    一、GIL锁1、全局解释器锁(GlobalInterpreterLock,简称GIL)GIL是一种用于保护Python解释器在多线程环境下的数据完整性的机制。GIL只存在是CPython解释器中,即官方的Python解释器实现GIL是一个互斥锁,你可以使用多线程来并发处理任务,但在同一时刻只能有一个线程......
  • mysql死锁问题排查SOP
    步骤1:查看写库的隔离级别#查看隔离级别showvariableslike'%tx_isolation%'或者select@@global.tx_isolationselect@@session.tx_isolation如果隔离级别为RC,则只有行锁,没有间隙锁。死锁概率会降低很多。步骤2:查看最近一次的死锁showengineinnodbstatus这个......