兰州计算机培训机构
服务热线:400-008-6280

兰州Linux培训班

兰州Linux培训班

  • 上课时段:详见详情
  • 教学点:1个
  • 开班时间:滚动开班
  • 课程价格:请咨询
  • 已关注:841
  • 优惠价格:请咨询
  • 咨询电话: 400-008-6280
授课学校:兰州计算机培训机构 (点击获取校区地址)

课程介绍

中公优就业Linux培训班

       中公优就业Linux云计算培训学员熟悉掌握Linux操作统的安装、配置、相关命令、VIM编辑器、系统管理、服务用和配置,并具有一定的实战能力。课程设置兼顾岗位学习难度、匹配未来就业岗位工作内容、岗位梯度,把学到的运用到工作当中去。


Linux云计算究竟为什么那么火?

百度、阿里巴巴、腾讯等国内排行靠前的互联网公司,大都使用的是Linux系统 



百度云

百度云

滴滴出行

滴滴出行

百度云有百万台服务器为企业提供云计算服务,这些服务都架构在Linux平台上。为了维持每天千万出行用户的使用,滴滴软件要保持极强的稳定性和安全性,这都需要专业的Linux运维工程师。

绝地求生

绝地求生

抖音

抖音

每一场战斗都需要毫秒级别的数据通信保障,这离不开在背后保驾护航的Linux云计算运维工程师。日活数亿的抖音软件中,数亿的视频都存储在专业的Linux系统存储平台上。



多岗位-多领域-多栖发展

五大职业方向平均薪资(数据来自职友集)

各岗位薪资
云计算工程师数据库运维工程师安全运维工程师系统运维工程师Python运维开发工程师
云计算研发工程师高级数据库工程师安全专家高级系统运维工程师Python高级运维开发工程师
云计算架构师数据库架构师安全架构师系统运维技术专家技术总监


课程适合人群


零基础人员

零基础人员

初高中辍学人员

初高中辍学人员

想转行人员

想转行人员

薪资低人员

薪资低人员

晋升无望人员

晋升无望人员

自制力强、学习态度好、能坚持,想通过学习改变现状的人员。初中高中毕业后就没有再继续学业的辍学人员。对IT行业感兴趣,想要转行Linux云计算行业的人员。目前薪资较低,但有更远大的抱负的人员。工作多年,却一直苦于无法晋升的人员。


精心研磨实用的良心课程 

课程兼顾实用与前沿,实时跟进市场动态,实操企业实战项目 


网络基础


第一阶段

学习内容

通信原理与通信网、 多路访问技术、 以太网通信技术、ISO/OSI开放系统互联模型、常用网络协议

信息编码与进制转换、MAC/IP地址与子网划分、网内网间通信模型

常用网络设备配置

企业级项目实战

IP地址配置与DNS解析

Linux运维项目IP地址配置与DNS解析

Linux基础


第二阶段

学习内容

计算机工作原理、操作系统基本原理、Linux操作系统

基础、Linux用户管理、Linux文件管理、Linux设备管理

Linux磁盘管理、Linux进程管理、Linux系统启动

Linux高级命令、Linux日常运维

企业级项目实战

云数据中心主机CPU资源利用率实时统计、分析系统

Linux运维项目CPU资源利用率实时统计、分析系统

Linux运维自动化


第三阶段

学习内容

Linux系统安全、文件共享服务、网络存储服务

常用网络服务、持续发布与持续集成、服务器集群与

高可用、Shell脚本编程、Python程序开发

企业级项目实战

Linux运维项目分布式监控系统部署与运维

1.Python+Shell实现企业级FTP文件统一管理

2.大型数据中心批量部署机器

3《OLG游戏》云平台弹性扩缩容设计与实现;《优选电商》云平台综合部署与日常运维

Linux运维项目分布式监控系统部署与运维

数据库 运维管理


第四阶段

学习内容

Linux系统安全、文件共享服务、网络存储服务

常用网络服务、持续发布与持续集成、服务器集群与

高可用、Shell脚本编程、Python程序开发

企业级项目实战

Linux运维项目异步消息队列集群部署与运维

1.企业级项目实战:MySQL Galera高可用集群环境部署

2.异步消息队列集群RabbitMQ部署与运维

3.企业ERP综合管理系统数据库设计与性能调优

Linux运维项目高可用集群环境部署

云数据中心综合运维


第五阶段

学习内容

虚拟化技术应用、企业云平台部署与管理

混合云与容器技术、云数据中心日常运维

项目实战与职业能力测评

企业级项目实战

Linux运维项目容器云平台部署与自动化运维

1.OpenStack虚拟化平台集群模式部署

2.Docker Swarm容器云平台部署与自动化运维

3《OLG游戏》云平台弹性扩缩容设计与实现;《优选电商》云平台综合部署与日常运维

Linux运维项目容器云平台部署与自动化运维

就业指导


第六阶段

简历制作、面试礼仪

模拟面试

       Linux培训资料

  Linux进程的睡眠和唤醒(干货)

  1 Linux进程的睡眠和唤醒

  在Linux中,仅等待CPU时间的进程称为就绪进程,它们被放置在一个运行队列中,一个就绪进程的状 态标志位为TASK_RUNNING。一旦一个运行中的进程时间片用完, Linux 内核的调度器会剥夺这个进程对CPU的控制权,并且从运行队列中选择一个合适的进程投入运行。

  当然,一个进程也可以主动释放CPU的控制权。函数 schedule()是一个调度函数,它可以被一个进程主动调用,从而调度其它进程占用CPU。一旦这个主动放弃CPU的进程被重新调度占用 CPU,那么它将从上次停止执行的位置开始执行,也就是说它将从调用schedule()的下一行代码处开始执行。

  有时候,进程需要等待直到某个特定的事件发生,例如设备初始化完成、I/O 操作完成或定时器到时等。在这种情况下,进程则必须从运行队列移出,加入到一个等待队列中,这个时候进程就进入了睡眠状态。

  Linux 中的进程睡眠状态有两种:一种是可中断的睡眠状态,其状态标志位TASK_INTERRUPTIBLE;

  另一种是不可中断 的睡眠状态,其状态标志位为TASK_UNINTERRUPTIBLE。可中断的睡眠状态的进程会睡眠直到某个条件变为真,比如说产生一个硬件中断、释放 进程正在等待的系统资源或是传递一个信号都可以是唤醒进程的条件。不可中断睡眠状态与可中断睡眠状态类似,但是它有一个例外,那就是把信号传递到这种睡眠 状态的进程不能改变它的状态,也就是说它不响应信号的唤醒。不可中断睡眠状态一般较少用到,但在一些特定情况下这种状态还是很有用的,比如说:进程必须等 待,不能被中断,直到某个特定的事件发生。

  在现代的Linux操作系统中,进程一般都是用调用schedule()的方法进入睡眠状态的,下面的代码演示了如何让正在运行的进程进入睡眠状态。

  sleeping_task = current;

  set_current_state(TASK_INTERRUPTIBLE);

  schedule();

  func1();

  /* Rest of the code ... */

  在第一个语句中,程序存储了一份进程结构指针sleeping_task,current 是一个宏,它指向正在执行的进程结构。set_current_state()将该进程的状态从执行状态TASK_RUNNING 变成睡眠状态TASK_INTERRUPTIBLE。 如果schedule()是被一个状态为TASK_RUNNING 的进程调度,那么schedule()将调度另外一个进程占用CPU;如果schedule()是被一个状态为TASK_INTERRUPTIBLE 或TASK_UNINTERRUPTIBLE 的进程调度,那么还有一个附加的步骤将被执行:当前执行的进程在另外一个进程被调度之前会被从运行队列中移出,这将导致正在运行的那个进程进入睡眠,因为 它已经不在运行队列中了。

  我们可以使用下面的这个函数将刚才那个进入睡眠的进程唤醒。

  wake_up_process(sleeping_task);

  在调用了wake_up_process()以后,这个睡眠进程的状态会被设置为TASK_RUNNING,而且调度器会把它加入到运行队列中去。当然,这个进程只有在下次被调度器调度到的时候才能真正地投入运行。

  2 无效唤醒

  几乎在所有的情况下,进程都会在检查了某些条件之后,发现条件不满足才进入睡眠。可是有的时候进程却会在 判定条件为真后开始睡眠,如果这样的话进程就会无限期地休眠下去,这就是所谓的无效唤醒问题。在操作系统中,当多个进程都企图对共享数据进行某种处理,而 最后的结果又取决于进程运行的顺序时,就会发生竞争条件,这是操作系统中一个典型的问题,无效唤醒恰恰就是由于竞争条件导致的。

  设想有两个进程A 和B,A 进程正在处理一个链表,它需要检查这个链表是否为空,如果不空就对链表里面的数据进行一些操作,同时B进程也在往这个链表添加节点。当这个链表是空的时候,由于无数据可操作,这时A进程就进入睡眠,当B进程向链表里面添加了节点之后它就唤醒A 进程,其代码如下:

  A进程:

  1 spin_lock(&list_lock);

  2 if(list_empty(&list_head)) {

  3 spin_unlock(&list_lock);

  4 set_current_state(TASK_INTERRUPTIBLE);

  5 schedule();

  6 spin_lock(&list_lock);

  7 }

  8

  9 /* Rest of the code ... */

  10 spin_unlock(&list_lock);

  B进程:

  100 spin_lock(&list_lock);

  101 list_add_tail(&list_head, new_node);

  102 spin_unlock(&list_lock);

  103 wake_up_process(processa_task);

  这里会出现一个问题,假如当A进程执行到第3行后第4行前的时候,B进程被另外一个处理器调度投 入运行。在这个时间片内,B进程执行完了它所有的指令,因此它试图唤醒A进程,而此时的A进程还没有进入睡眠,所以唤醒操作无效。在这之后,A 进程继续执行,它会错误地认为这个时候链表仍然是空的,于是将自己的状态设置为TASK_INTERRUPTIBLE然后调用schedule()进入睡 眠。由于错过了B进程唤醒,它将会无限期的睡眠下去,这就是无效唤醒问题,因为即使链表中有数据需要处理,A 进程也还是睡眠了。

  3 避免无效唤醒

  如何避免无效唤醒问题呢?我们发现无效唤醒主要发生在检查条件之后和进程状态被设置为睡眠状态之前, 本来B进程的wake_up_process()提供了一次将A进程状态置为TASK_RUNNING 的机会,可惜这个时候A进程的状态仍然是TASK_RUNNING,所以wake_up_process()将A进程状态从睡眠状态转变为运行状态的努力 没有起到预期的作用。要解决这个问题,必须使用一种保障机制使得判断链表为空和设置进程状态为睡眠状态成为一个不可分割的步骤才行,也就是必须消除竞争条 件产生的根源,这样在这之后出现的wake_up_process ()就可以起到唤醒状态是睡眠状态的进程的作用了。

  找到了原因后,重新设计一下A进程的代码结构,就可以避免上面例子中的无效唤醒问题了。

  A进程:

  1 set_current_state(TASK_INTERRUPTIBLE);

  2 spin_lock(&list_lock);

  3 if(list_empty(&list_head)) {

  4 spin_unlock(&list_lock);

  5 schedule();

  6 spin_lock(&list_lock);

  7 }

  8 set_current_state(TASK_RUNNING);

  9

  10 /* Rest of the code ... */

  11 spin_unlock(&list_lock);

  可以看到,这段代码在测试条件之前就将当前执行进程状态转设置成TASK_INTERRUPTIBLE了,并且在链表不为空的情况下又将自己置为TASK_RUNNING状态。这样一来如果B进程在A进程进程检查了链表为空以后调用wake_up_process(),那么A进程的状态就会自动由原来TASK_INTERRUPTIBLE

  变成TASK_RUNNING,此后即使进程又调用了schedule(),由于它现在的状态是TASK_RUNNING,所以仍然不会被从运行队列中移出,因而不会错误的进入睡眠,当然也就避免了无效唤醒问题。

  4 Linux内核的例子

  在Linux操作系统中,内核的稳定性至关重要,为了避免在Linux操作系统内核中出现无效唤醒问题,Linux内核在需要进程睡眠的时候应该使用类似如下的操作:

  /* ‘q’是我们希望睡眠的等待队列 */

  DECLARE_WAITQUEUE(wait,current);

  add_wait_queue(q, &wait);

  set_current_state(TASK_INTERRUPTIBLE);

  /* 或TASK_INTERRUPTIBLE */

  while(!condition) /* ‘condition’ 是等待的条件*/

  schedule();

  set_current_state(TASK_RUNNING);

  remove_wait_queue(q, &wait);

  上面的操作,使得进程通过下面的一系列步骤安全地将自己加入到一个等待队列中进行睡眠:首先调用DECLARE_WAITQUEUE ()创建一个等待队列的项,然后调用add_wait_queue()把自己加入到等待队列中,并且将进程的状态设置为 TASK_INTERRUPTIBLE 或者TASK_INTERRUPTIBLE。然后循环检查条件是否为真:如果是的话就没有必要睡眠,如果条件不为真,就调用schedule()。当进程 检查的条件满足后,进程又将自己设置为TASK_RUNNING 并调用remove_wait_queue()将自己移出等待队列。

  从上面可以看到,Linux的内核代码维护者也是在进程检查条件之前就设置进程的状态为睡眠状态,然后才循环检查条件。如果在进程开始睡眠之前条件就已经达成了,那么循环会退出并用set_current_state()将自己的状态设置为就绪,这样同样保证了进程不会存在错误的进入睡眠的倾向,当然也就不会导致出现无效唤醒问题。

  下面让我们用linux 内核中的实例来看看Linux 内核是如何避免无效睡眠的,这段代码出自Linux2.6的内核(linux-2.6.11/kernel/sched.c: 4254):

  4253 /* Wait for kthread_stop */

  4254 set_current_state(TASK_INTERRUPTIBLE);

  4255 while (!kthread_should_stop()) {

  4256 schedule();

  4257 set_current_state(TASK_INTERRUPTIBLE);

  4258 }

  4259 __set_current_state(TASK_RUNNING);

  4260 return 0;

  上面的这些代码属于迁移服务线程migration_thread,这个线程不断地检查kthread_should_stop(),直到kthread_should_stop()返回1它才可以退出循环,也就是说只要kthread_should_stop()返回0该进程就会一直睡 眠。从代码中我们可以看出,检查kthread_should_stop()确实是在进程的状态被置为TASK_INTERRUPTIBLE后才开始执行 的。因此,如果在条件检查之后但是在schedule()之前有其他进程试图唤醒它,那么该进程的唤醒操作不会失效。

  小结

  通过上面的讨论,可以发现在Linux 中避免进程的无效唤醒的关键是在进程检查条件之前就将进程的状态置为TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE,并且如果检查的条件满足的话就应该将其状态重新设置为TASK_RUNNING。这样无论进程等待的条件是否满足, 进程都不会因为被移出就绪队列而错误地进入睡眠状态,从而避免了无效唤醒问题。


扫描二维码免费领取试听课程

报名预约

登录51乐学网

注册51乐学网

免费短信关闭