Linux多线程(Linux多线程压缩文件)

Linux多线程int main() { pthread_t tid[5]; for(int i0;i<5;i) { int* idnew int(i); pthread_create(tidi,nullptr,ThreadRoutine,

int main()

{

pthread_t tid[5];

for(int i=0;i5;i++)

{

int* id=新int(i);

pthread_create(tid+i,nullptr,ThreadRoutine,(void*)id);//创建5个线程,这里传递ID而不是i。毕竟,更改i 值的线程是因为地址传递给了它。

}

for(int i=0;i5;i++)

{

pthread_join(tid[i],nullptr);//等待线程

}

返回0。

}

我们希望这5 个线程抢购所有1,000 张门票(直到有0 张门票)。然而,结果并没有像我预期的那么多票,而且我发现有些线程收到了负票。

![在此插入图片描述](https://img-blog.csdnimg.cn/6597a3a694dc4063809e62fe991c877c.png)

此时,我们意识到虽然票据是一个关键资源,但线程安全并不能得到保证。

那么为什么会发生这种情况呢?

###(二)基本原则

作为关键资源,票证必须由所有线程进行评估,以确定票证是否大于0 并执行票证操作。例如,票据操作看起来像一行C 代码,但底层汇编实际上经历了三个阶段:加载命令、减去命令和存储命令。

由于线程总是会切换,因此线程有可能在执行加载命令之后但在执行减法或写回操作之前进行切换。 CPU开始执行下一个线程。

![在此插入图片描述](https://img-blog.csdnimg.cn/1e25c653e4de4d8b821acb396839288a.png)

当线程A分离时,线程A保留临时数据(尚未来得及执行操作的1000条数据)。这时,线程B进来了。这假设您执行的操作成功将票证设置为10 并将它们写回内存。

一段时间后,线程A 返回临时数据1000。线程A认为票据值仍然是原来的1000,因此执行-操作将值更改为999并写回内存。 **写回过程会覆盖B原来写回的数据。 B先生被白白处决了。 **

所以我发现当多个线程同时运行时这是一个非常令人困惑的情况。

还可以分析一下线程在执行决策操作时突然切换,发现ticket大于0(此时还没有ticket提交给CPU)的情况。另一个线程到来并将票据设置为0。至此,原来的线程大概已经确定了票的大小。我们得到tick值后,直接放入CPU进行计算,所以我们看到的是一个负数。

为了解决这个问题,我们引入了线程锁的概念。

## 4.螺丝锁紧

### 1. 使用锁

对于上述问题,只要保证一个线程在其他线程操作票证时不操作该票证就足够了。 (请注意,我们不保证线不会断。)

要使用线程锁,需要了解线程锁的一种类型和四种相关函数。

#### (1)初始化与销毁

![在此插入图片描述](https://img-blog.csdnimg.cn/1529ae61ace04cec845ec04e1dc18e0c.png)

参数pthread\\_mutex\\_t是锁类型,用于定义锁。

函数pthread\\_mutex\\_init是用于初始化的函数。第一个参数是指向要初始化的锁的指针。第二个参数可以设置为NULL。

函数pthread\\_mutex\\_destroy是一个锁销毁函数,它的参数指向被销毁的锁。

#### (2) 锁定和解锁

![在此插入图片描述](https://img-blog.csdnimg.cn/d6ccb4c18a934aa3b1ad895ec5e63186.png)

函数pthread\\_mutex\\_lock 是锁定函数,pthread\\_mutex\\_unlock 是解锁函数。

只需在访问临界资源区域(临界区)之前对其进行锁定,然后在访问之后释放锁,就可以确保当一个线程访问临界资源时,其他线程无法访问该资源。

### 2. 门票获取逻辑

包括

包括

#includeunistd.h

#include Depthread.h

#includestdio.h

使用命名空间标准。

班级票

{

私人:

pthread_mutex_t mtx;//定义锁

int Ticket=1000; //定义票数。

公共:

门票():门票(1000)

{

pthread_mutex_init(mtx,nullptr);//在构造函数中初始化锁

}

布尔获取票证()

{

布尔值=真;

pthread_mutex_lock(mtx); //对关键资源门票的访问必须被锁定

如果(票0)

{

我们睡觉(1000);

cout \”我有\”pthread_self()\” 这是我得到的票: \”ticketsendl;

票-;

}

除此之外

{

响应=假;

cout “门票已售完” endl;

printf(\”\”);

}

pthread_mutex_unlock(mtx);//结束访问,解锁

返回响应。

}

门票()

{

pthread_mutex_destroy(mtx);//在析构函数中销毁锁

}

};

void* ThreadRoutine(void* args)

{

票* t=(票*)args;

cout \”我是一个线程\” pthread_self()endl;

同时(正确)

{

if(t-GetTicket())

{

继续;

}

除此之外

{

休息;

}

}

}

int main()

{

票* t=新票();

pthread_t tid[5];

for(int i=0;i5;i++)

{

pthread_create(tid+i,nullptr,ThreadRoutine,(void*)t);

}

for(int i=0;i5;i++)

{

pthread_join(tid[i],nullptr);

}

返回0。

}

要实现此过程,请定义一个定义票证和锁的Ticket 类。访问函数允许线程访问锁并对关键部分执行锁定和解锁操作。

如果此时再次运行代码,您将看到票证检索结果符合预期。

![在此插入图片描述](https://img-blog.csdnimg.cn/8e6c464b2b6c4071aba717c2cde9929f.png)

您还可以使用C++ 提供的函数执行锁定操作。必须包含头文件mux。

mutex mymtx //定义锁

mymtx.lock();//锁定

mymtx.unlock; //解锁。

您还可以定义静态锁,不需要调用任何初始化或销毁函数。

静态pthread\\_mutex\\_t mtx:PTHREAD\\_MUTEX\\_INITIALIZER

### 3.锁原理

事实证明,票据是一种对所有线程都可见的资源,因此是一种重要的资源。锁也是所有线程可见的资源,那么为什么不存在线程安全问题呢?这是因为加锁和解锁过程是原子的。重要的是, 仅使用一个组件来交换内存中的数据与CPU 寄存器中的数据。

其汇编代码为:

锁:

将值movb $0,%al #0 分配给注册

xchgb %al,mutex #将内存中的互斥量值与寄存器中的数据交换

if(寄存器内容为0)

{

返回0。

}

除此之外

{

暂停并等待。

}

去锁吧。

解锁:

movb $1 互斥体

启动一个等待互斥体的线程。

返回0

要理解这个过程,您必须首先理解上下文数据的概念。事实上,线程切换后,其PCB中存储着执行数据。

![在此插入图片描述](https://img-blog.csdnimg.cn/2e436866ff2b4f4a80757bb74277429b.png)

当线程A 到达时,假设它正在尝试获取锁,但此时没有其他线程到达得那么快。寄存器al中的数据变为0。执行交换操作,将内存中互斥体的值交换到A中寄存器al。此时线程A的al值为1,线程A的mutex值为1。内存为0。

当线程A切换时(上下文数据为1切换),线程B到来,其al寄存器的值为0(线程设置自己的上下文数据互不冲突),线程B进行交换。如果mutex的值和al寄存器的值(0和0交换),B最终得到的值将是0,就会出现挂起等待。此时,我们可以根据每个线程的al寄存器的值来确定哪个线程获取了锁,这样只有该线程才能访问临时资源。当A完成对资源的访问时,它释放锁,唤醒等待线程,并将互斥锁值设置为1。

注意,获得锁的A在访问临时资源时仍然处于切换状态,但此时没有其他线程可以访问临时资源。

从其他线程的角度来看,A在没有申请锁的情况下无法访问关键资源,或者A在申请锁后访问了关键资源。因此,线程A 访问关键资源的操作是原子的。

## 5. 死锁

### 1. 概念

死锁是指进程组中的每个进程都占用了一个不会被释放的资源,但该进程由于相互请求被其他进程占用且不会被释放的资源而处于等待状态的情况。对事物。

### 2.死锁的四个要求

互斥条件:一种资源只能在一个执行流中使用。

请求和保留条件:如果对资源的请求阻塞了执行流程,则所获取的资源将被保留。

不剥夺条件:执行流获取的资源在耗尽之前不能被强行剥夺。

循环等待条件:多个执行流之间的正式参数关系,其中循环端到端地等待资源。

### 3.如何避免死锁

打破僵局需要四个条件。

锁定顺序是一致的。

避免锁被锁定但从未释放的情况。

资源分配一次。

### 4.避免死锁算法

死锁检测算法

我们整理了数百道**【运维技术栈面试题】**,成为您运维面试的得力助手。这将帮助您在面试时不慌不忙,并为高质量的面试做好准备。付费报价!

这些面试题涵盖了从Shell、MySQL到K8等云原生技术栈,不仅适合运维行业新人的面试需求,也适合对运维感兴趣的朋友是适合的。升职或换工作以增加薪水。 **

![](https://img-blog.csdnimg.cn/img_convert/620fa51806c0aab9c2627db7902db488.png)

本次访谈集内容为

* **174 运维工程师面试题**

* **128道k8s面试题**

* **108 个shell 脚本面试问题**

* **200 个Linux 面试问题**

* **51 个Docker 面试问题**

* **35 个Jenkis 面试问题**

* **78 MongoDB 面试问题**

* **17 Ansible 面试问题**

* **60 个Dubbo 面试问题**

* **53 次卡夫卡访谈**

* **18道mysql面试题**

* **40 个nginx 面试题**

* **77 个Redis 面试问题**

* **28 守门员**

**总共1000多道面试题,内容丰富、信息丰富**

* **174 运维工程师面试题**

1.什么是运维?

2、运维人员在工作场所经常需要与操作人员进行交互。运营人员做什么工作?

3. 给定300台服务器,如何管理它们?

4、我们简单解释一下raid0、raid1和raid5这两种运行模式的运行原理和特点。

5、LVS、Nginx、HAproxy有什么区别,工作中如何选择?

6. Squid、Varinsh、Nginx 有什么区别,你在工作中如何选择?

7.Tomcat和Resin有什么区别?

8.什么是中间件?

9. Tomcat 的三个端口8005、8009、8080 是什么意思?

10.什么是CDN?

11.什么是网站灰度发布?

12、请简单说明一下DNS域名解析的过程。

13.什么是RabbitMQ?

14.Keepalived如何工作?

15.描述LVS工作流程的三种模式。

16、mysql的innodb如何识别锁定问题以及mysql如何减少主从复制延迟?

工作中arinsh和Nginx有什么区别?

7.Tomcat和Resin有什么区别?

8.什么是中间件?

9. Tomcat 的三个端口8005、8009、8080 是什么意思?

10.什么是CDN?

11.什么是网站灰度发布?

12、请简单说明一下DNS域名解析的过程。

13.什么是RabbitMQ?

14.Keepalived如何工作?

15.描述LVS工作流程的三种模式。

16、mysql的innodb如何识别锁定问题以及mysql如何减少主从复制延迟?

17.如何重置mysql root密码?

以上关于#Linux多线程的相关内容摘自网络,仅供参考。相关信息请参见官方公告。

原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/91192.html

(0)
CSDN's avatarCSDN
上一篇 2024年6月21日 下午6:50
下一篇 2024年6月21日 下午6:50

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注