死锁,死锁的四个必要条件以及处理策略

2023-05-16

  • 一、什么是死锁
  • 二、死锁与饥饿
  • 三、资源的类型
    • 3.1 可重用资源和消耗性资源
      • 3.1.1 可重用资源(永久性资源)
      • 3.1.2 消耗性资源(临时性资源)
    • 3.2 可抢占资源和不可抢占资源
      • 3.2.1 可抢占资源
      • 3.2.2 不可抢占资源
  • 四、死锁产生的原因
    • 4.1 竞争不可抢占资源引起死锁
    • 4.2 竞争可消耗资源引起死锁
    • 4.3 进程推进顺序不当引起死锁
  • 五、产生死锁的四个必要条件
    • 5.1 互斥条件:
    • 5.2 不可剥夺条件:
    • 5.3 请求与保持条件:
    • 5.4 循环等待条件:
  • 六、处理死锁的方法
    • 6.1 预防死锁
    • 6.2 避免死锁
      • 6.2.1 常用避免死锁的方法
        • 6.2.1.1 有序资源分配法
        • 6.2.1.2 银行家算法
      • 6.2.2 常用避免死锁的技术
        • 6.2.2.1 加锁顺序
        • 6.2.2.2 加锁时限
        • 6.2.2.3 死锁检测
    • 6.3 检测死锁
    • 6.4 解除死锁

一、什么是死锁

多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力。然而,并发执行也带来了新的问题——死锁。
死锁是指两个或两个以上的进程(线程)在运行过程中因争夺资源而造成的一种僵局(Deadly-Embrace) ) ,若无外力作用,这些进程(线程)都将无法向前推进。

下面我们通过一些实例来说明死锁现象。

先看生活中的一个实例,2个人一起吃饭但是只有一双筷子,2人轮流吃(同时拥有2只筷子才能吃)。某一个时候,一个拿了左筷子,一人拿了右筷子,2个人都同时占用一个资源,等待另一个资源,这个时候甲在等待乙吃完并释放它占有的筷子,同理,乙也在等待甲吃完并释放它占有的筷子,这样就陷入了一个死循环,谁也无法继续吃饭。。。
在计算机系统中也存在类似的情况。例如,某计算机系统中只有一台打印机和一台输入设备,进程P1正占用输入设备,同时又提出使用打印机的请求,但此时打印机正被进程P2 所占用,而P2在未释放打印机之前,又提出请求使用正被P1占用着的输入设备。这样两个进程相互无休止地等待下去,均无法继续执行,此时两个进程陷入死锁状态。

关于死锁的一些结论:

  • 参与死锁的进程数至少为两个
  • 参与死锁的所有进程均等待资源
  • 参与死锁的进程至少有两个已经占有资源
  • 死锁进程是系统中当前进程集合的一个子集
  • 死锁会浪费大量系统资源,甚至导致系统崩溃。

二、死锁与饥饿

饥饿(Starvation)指一个进程一直得不到资源。

死锁和饥饿都是由于进程竞争资源而引起的。饥饿一般不占有资源,死锁进程一定占有资源。

三、资源的类型

3.1 可重用资源和消耗性资源

3.1.1 可重用资源(永久性资源)

可被多个进程多次使用,如所有硬件。

  • 只能分配给一个进程使用,不允许多个进程共享。
  • 进程在对可重用资源的使用时,须按照请求资源、使用资源、释放资源这样的顺序。
  • 系统中每一类可重用资源中的单元数目是相对固定的,进程在运行期间,既不能创建,也不能删除。

3.1.2 消耗性资源(临时性资源)

又称临时性资源,是由进程在运行期间动态的创建和消耗的。

  • 消耗性资源在进程运行期间是可以不断变化的,有时可能为0。
  • 进程在运行过程中,可以不断地创造可消耗性资源的单元,将它们放入该资源类的缓冲区中,以增加该资源类的单元数目。
  • 进程在运行过程中,可以请求若干个可消耗性资源单元,用于进程自己消耗,不再将它们返回给该资源类中。

可消耗资源通常是由生产者进程创建,由消费者进程消耗。最典型的可消耗资源是用于进程间通信的消息。

3.2 可抢占资源和不可抢占资源

3.2.1 可抢占资源

可抢占资源指某进程在获得这类资源后,该资源可以再被其他进程或系统抢占。对于这类资源是不会引起死锁的。

CPU 和主存均属于可抢占性资源。

3.2.2 不可抢占资源

一旦系统把某资源分配给该进程后,就不能将它强行收回,只能在进程用完后自行释放。

磁带机、打印机等属于不可抢占性资源。

四、死锁产生的原因

  • 竞争不可抢占资源引起死锁
    通常系统中拥有的不可抢占资源,其数量不足以满足多个进程运行的需要,使得进程在运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。只有对不可抢占资源的竞争 才可能产生死锁,对可抢占资源的竞争是不会引起死锁的。
  • 竞争可消耗资源引起死锁
  • 进程推进顺序不当引起死锁
    进程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。例如,并发进程 P1、P2分别保持了资源R1、R2,而进程P1申请资源R2,进程P2申请资源R1时,两者都会因为所需资源被占用而阻塞。
    信号量使用不当也会造成死锁。进程间彼此相互等待对方发来的消息,结果也会使得这 些进程间无法继续向前推进。例如,进程A等待进程B发的消息,进程B又在等待进程A 发的消息,可以看出进程A和B不是因为竞争同一资源,而是在等待对方的资源导致死锁。

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

如:共享文件时引起死锁
系统中拥有两个进程P1和P2,它们都准备写两个文件F1和F2。而这两者都属于可重用和不可抢占性资源。如果进程P1在打开F1的同时,P2进程打开F2文件,当P1想打开F2时由于F2已结被占用而阻塞,当P2想打开1时由于F1已结被占用而阻塞,此时就会无线等待下去,形成死锁。
这里写图片描述

4.2 竞争可消耗资源引起死锁

如:进程通信时引起死锁
系统中拥有三个进程P1、P2和P3,m1、m2、m3是3可消耗资源。进程P1一方面产生消息m1,将其发送给P2,另一方面要从P3接收消息m3。而进程P2一方面产生消息m2,将其发送给P3,另一方面要从P1接收消息m1。类似的,进程P3一方面产生消息m3,将其发送给P1,另一方面要从P2接收消息m2。
如果三个进程都先发送自己产生的消息后接收别人发来的消息,则可以顺利的运行下去不会产生死锁,但要是三个进程都先接收别人的消息而不产生消息则会永远等待下去,产生死锁。
这里写图片描述

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

这里写图片描述
上图中,如果按曲线1的顺序推进,两个进程可顺利完成;如果按曲线2的顺序推进,两个进程可顺利完成;如果按曲线3的顺序推进,两个进程可顺利完成;如果按曲线4的顺序推进,两个进程将进入不安全区D中,此时P1保持了资源R1,P2保持了资源R2,系统处于不安全状态,如果继续向前推进,则可能产生死锁。

五、产生死锁的四个必要条件

5.1 互斥条件:

进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。

5.2 不可剥夺条件:

进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)。

5.3 请求与保持条件:

进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。

5.4 循环等待条件:

存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被 链中下一个进程所请求。即存在一个处于等待状态的进程集合{Pl, P2, …, pn},其中Pi等 待的资源被P(i+1)占有(i=0, 1, …, n-1),Pn等待的资源被P0占有,如图2-15所示。

直观上看,循环等待条件似乎和死锁的定义一样,其实不然。按死锁定义构成等待环所 要求的条件更严,它要求Pi等待的资源必须由P(i+1)来满足,而循环等待条件则无此限制。 例如,系统中有两台输出设备,P0占有一台,PK占有另一台,且K不属于集合{0, 1, …, n}。

Pn等待一台输出设备,它可以从P0获得,也可能从PK获得。因此,虽然Pn、P0和其他 一些进程形成了循环等待圈,但PK不在圈内,若PK释放了输出设备,则可打破循环等待, 如图2-16所示。因此循环等待只是死锁的必要条件。

这里写图片描述

资源分配图含圈而系统又不一定有死锁的原因是同类资源数大于1。但若系统中每类资 源都只有一个资源,则资源分配图含圈就变成了系统出现死锁的充分必要条件。

以上这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

产生死锁的一个例子:

/**
 * 一个简单的死锁类
 * 当DeadLock类的对象flag==1时(td1),先锁定o1,睡眠500毫秒
 * 而td1在睡眠的时候另一个flag==0的对象(td2)线程启动,先锁定o2,睡眠500毫秒
 * td1睡眠结束后需要锁定o2才能继续执行,而此时o2已被td2锁定;
 * td2睡眠结束后需要锁定o1才能继续执行,而此时o1已被td1锁定;
 * td1、td2相互等待,都需要得到对方锁定的资源才能继续执行,从而死锁。
 */
public class DeadLock implements Runnable {
    public int flag = 1;  
    //静态对象是类的所有对象共享的  
    private static Object o1 = new Object(), o2 = new Object();  
    @Override  
    public void run() {  
        System.out.println("flag=" + flag);  
        if (flag == 1) {  
            synchronized (o1) {  
                try {  
                    Thread.sleep(500);  
                } catch (Exception e) {  
                    e.printStackTrace();  
                }  
                synchronized (o2) {  
                    System.out.println("1");  
                }  
            }  
        }  
        if (flag == 0) {  
            synchronized (o2) {  
                try {  
                    Thread.sleep(500);  
                } catch (Exception e) {  
                    e.printStackTrace();  
                }  
                synchronized (o1) {  
                    System.out.println("0");  
                }  
            }  
        }  
    }  

    public static void main(String[] args) {
        DeadLock td1 = new DeadLock();
        DeadLock td2 = new DeadLock();
        td1.flag = 1;
        td2.flag = 0;
        //td1,td2都处于可执行状态,但JVM线程调度先执行哪个线程是不确定的。  
        //td2的run()可能在td1的run()之前运行  
        new Thread(td1).start();  
        new Thread(td2).start();
    }  
}  

六、处理死锁的方法

  • 预防死锁:通过设置某些限制条件,去破坏产生死锁的四个必要条件中的一个或几个条件,来防止死锁的发生。
  • 避免死锁:在资源的动态分配过程中,用某种方法去防止系统进入不安全状态,从而避免死锁的发生。
  • 检测死锁:允许系统在运行过程中发生死锁,但可设置检测机构及时检测死锁的发生,并采取适当措施加以清除。
  • 解除死锁:当检测出死锁后,便采取适当措施将进程从死锁状态中解脱出来。

6.1 预防死锁

  1. 破坏“互斥”条件:
    就是在系统里取消互斥。若资源不被一个进程独占使用,那么死锁是肯定不会发生的。但一般来说在所列的四个条件中,“互斥”条件是无法破坏的。因此,在死锁预防里主要是破坏其他几个必要条件,而不去涉及破坏“互斥”条件。

    注意:互斥条件不能被破坏,否则会造成结果的不可再现性。

  2. 破坏“占有并等待”条件:
    破坏“占有并等待”条件,就是在系统中不允许进程在已获得某种资源的情况下,申请其他资源。即要想出一个办法,阻止进程在持有资源的同时申请其他资源。
    方法一:创建进程时,要求它申请所需的全部资源,系统或满足其所有要求,或什么也不给它。这是所谓的 “ 一次性分配”方案。
    方法二:要求每个进程提出新的资源申请前,释放它所占有的资源。这样,一个进程在需要资源S时,须先把它先前占有的资源R释放掉,然后才能提出对S的申请,即使它可能很快又要用到资源R。

  3. 破坏“不可抢占”条件:
    破坏“不可抢占”条件就是允许对资源实行抢夺。
    方法一:如果占有某些资源的一个进程进行进一步资源请求被拒绝,则该进程必须释放它最初占有的资源,如果有必要,可再次请求这些资源和另外的资源。
    方法二:如果一个进程请求当前被另一个进程占有的一个资源,则操作系统可以抢占另一个进程,要求它释放资源。只有在任意两个进程的优先级都不相同的条件下,方法二才能预防死锁。

  4. 破坏“循环等待”条件:
    破坏“循环等待”条件的一种方法,是将系统中的所有资源统一编号,进程可在任何时刻提出资源申请,但所有申请必须按照资源的编号顺序(升序)提出。这样做就能保证系统不出现死锁。

6.2 避免死锁

理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。所以,在系统设计、进程调度等方面注意如何让这四个必要条件不成立,如何确定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的情况下占用资源。因此,对资源的分配要给予合理的规划。

预防死锁和避免死锁的区别:
预防死锁是设法至少破坏产生死锁的四个必要条件之一,严格的防止死锁的出现,而避免死锁则不那么严格的限制产生死锁的必要条件的存在,因为即使死锁的必要条件存在,也不一定发生死锁。避免死锁是在系统运行过程中注意避免死锁的最终发生。

6.2.1 常用避免死锁的方法

6.2.1.1 有序资源分配法

这种算法资源按某种规则系统中的所有资源统一编号(例如打印机为1、磁带机为2、磁盘为3、等等),申请时必须以上升的次序。系统要求申请进程:
  1、对它所必须使用的而且属于同一类的所有资源,必须一次申请完;
  2、在申请不同类资源时,必须按各类设备的编号依次申请。例如:进程PA,使用资源的顺序是R1,R2; 进程PB,使用资源的顺序是R2,R1;若采用动态分配有可能形成环路条件,造成死锁。
  采用有序资源分配法:R1的编号为1,R2的编号为2;
  PA:申请次序应是:R1,R2
  PB:申请次序应是:R1,R2
  这样就破坏了环路条件,避免了死锁的发生。
  

6.2.1.2 银行家算法

详见银行家算法.

6.2.2 常用避免死锁的技术

  1. 加锁顺序(线程按照一定的顺序加锁)
  2. 加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
  3. 死锁检测

6.2.2.1 加锁顺序

当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就很容易发生。

如果能确保所有的线程都是按照相同的顺序获得锁,那么死锁就不会发生。看下面这个例子:

Thread 1:
lock A
lock B
Thread 2:
wait for A
lock C (when A locked)
Thread 3:
wait for A
wait for B
wait for C

如果一个线程(比如线程3)需要一些锁,那么它必须按照确定的顺序获取锁。它只有获得了从顺序上排在前面的锁之后,才能获取后面的锁。

例如,线程2和线程3只有在获取了锁A之后才能尝试获取锁C(译者注:获取锁A是获取锁C的必要条件)。因为线程1已经拥有了锁A,所以线程2和3需要一直等到锁A被释放。然后在它们尝试对B或C加锁之前,必须成功地对A加了锁。

按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要你事先知道所有可能会用到的锁(译者注:并对这些锁做适当的排序),但总有些时候是无法预知的。

6.2.2.2 加锁时限

另外一个可以避免死锁的方法是在尝试获取锁的时候加一个超时时间,这也就意味着在尝试获取锁的过程中若超过了这个时限该线程则放弃对该锁请求。若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,然后等待一段随机的时间再重试。这段随机的等待时间让其它线程有机会尝试获取相同的这些锁,并且让该应用在没有获得锁的时候可以继续运行(译者注:加锁超时后可以先继续运行干点其它事情,再回头来重复之前加锁的逻辑)。

以下是一个例子,展示了两个线程以不同的顺序尝试获取相同的两个锁,在发生超时后回退并重试的场景:

Thread 1 locks A
Thread 2 locks B
Thread 1 attempts to lock B but is blocked
Thread 2 attempts to lock A but is blocked
Thread 1’s lock attempt on B times out
Thread 1 backs up and releases A as well
Thread 1 waits randomly (e.g. 257 millis) before retrying.
Thread 2’s lock attempt on A times out
Thread 2 backs up and releases B as well
Thread 2 waits randomly (e.g. 43 millis) before retrying.

在上面的例子中,线程2比线程1早200毫秒进行重试加锁,因此它可以先成功地获取到两个锁。这时,线程1尝试获取锁A并且处于等待状态。当线程2结束时,线程1也可以顺利的获得这两个锁(除非线程2或者其它线程在线程1成功获得两个锁之前又获得其中的一些锁)。

需要注意的是,由于存在锁的超时,所以我们不能认为这种场景就一定是出现了死锁。也可能是因为获得了锁的线程(导致其它线程超时)需要很长的时间去完成它的任务。

此外,如果有非常多的线程同一时间去竞争同一批资源,就算有超时和回退机制,还是可能会导致这些线程重复地尝试但却始终得不到锁。如果只有两个线程,并且重试的超时时间设定为0到500毫秒之间,这种现象可能不会发生,但是如果是10个或20个线程情况就不同了。因为这些线程等待相等的重试时间的概率就高的多(或者非常接近以至于会出现问题)。
(译者注:超时和重试机制是为了避免在同一时间出现的竞争,但是当线程很多时,其中两个或多个线程的超时时间一样或者接近的可能性就会很大,因此就算出现竞争而导致超时后,由于超时时间一样,它们又会同时开始重试,导致新一轮的竞争,带来了新的问题。)

这种机制存在一个问题,在Java中不能对synchronized同步块设置超时时间。你需要创建一个自定义锁,或使用Java5中java.util.concurrent包下的工具。写一个自定义锁类不复杂,但超出了本文的内容。后续的Java并发系列会涵盖自定义锁的内容。

6.2.2.3 死锁检测

死锁检测是一个更好的死锁预防机制,它主要是针对那些不可能实现按序加锁并且锁超时也不可行的场景。

每当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。

当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。例如,线程A请求锁7,但是锁7这个时候被线程B持有,这时线程A就可以检查一下线程B是否已经请求了线程A当前所持有的锁。如果线程B确实有这样的请求,那么就是发生了死锁(线程A拥有锁1,请求锁7;线程B拥有锁7,请求锁1)。

当然,死锁一般要比两个线程互相持有对方的锁这种情况要复杂的多。线程A等待线程B,线程B等待线程C,线程C等待线程D,线程D又在等待线程A。线程A为了检测死锁,它需要递进地检测所有被B请求的锁。从线程B所请求的锁开始,线程A找到了线程C,然后又找到了线程D,发现线程D请求的锁被线程A自己持有着。这是它就知道发生了死锁。

下面是一幅关于四个线程(A,B,C和D)之间锁占有和请求的关系图。像这样的数据结构就可以被用来检测死锁。

这里写图片描述

6.3 检测死锁

一般来说,由于操作系统有并发,共享以及随机性等特点,通过预防和避免的手段达到排除死锁的目的是很困难的。这需要较大的系统开销,而且不能充分利用资源。为此,一种简便的方法是系统为进程分配资源时,不采取任何限制性措施,但是提供了检测和解脱死锁的手段:能发现死锁并从死锁状态中恢复出来。因此,在实际的操作系统中往往采用死锁的检测与恢复方法来排除死锁。
死锁检测与恢复是指系统设有专门的机构,当死锁发生时,该机构能够检测到死锁发生的位置和原因,并能通过外力破坏死锁发生的必要条件,从而使得并发进程从死锁状态中恢复出来。
这时进程P1占有资源R1而申请资源R2,进程P2占有资源R2而申请资源R1,按循环等待条件,进程和资源形成了环路,所以系统是死锁状态。进程P1,P2是参与死锁的进程。
下面我们再来看一看死锁检测算法。算法使用的数据结构是如下这些:
占有矩阵A:n*m阶,其中n表示并发进程的个数,m表示系统的各类资源的个数,这个矩阵记录了每一个进程当前占有各个资源类中资源的个数。
申请矩阵R:n*m阶,其中n表示并发进程的个数,m表示系统的各类资源的个数,这个矩阵记录了每一个进程当前要完成工作需要申请的各个资源类中资源的个数。
空闲向量T:记录当前m个资源类中空闲资源的个数。
完成向量F:布尔型向量值为真(true)或假(false),记录当前n个并发进程能否进行完。为真即能进行完,为假则不能进行完。
临时向量W:开始时W:=T。
算法步骤:
(1)W:=T,
对于所有的i=1,2,…,n,
如果A[i]=0,则F[i]:=true;否则,F[i]:=false
(2)找满足下面条件的下标i:
F[i]:=false并且R[i]〈=W
如果不存在满足上面的条件i,则转到步骤(4)。
(3)W:=W+A[i]
F[i]:=true
转到步骤(2)
(4)如果存在i,F[i]:=false,则系统处于死锁状态,且Pi进程参与了死锁。什么时候进行死锁的检测取决于死锁发生的频率。如果死锁发生的频率高,那么死锁检测的频率也要相应提高,这样一方面可以提高系统资源的利用率,一方面可以避免更多的进程卷入死锁。如果进程申请资源不能满足就立刻进行检测,那么每当死锁形成时即能被发现,这和死锁避免的算法相近,只是系统的开销较大。为了减小死锁检测带来的系统开销,一般采取每隔一段时间进行一次死锁检测,或者在CPU的利用率降低到某一数值时,进行死锁的检测。

6.4 解除死锁

一旦检测出死锁,就应立即釆取相应的措施,以解除死锁。
死锁解除的主要方法有:
1) 资源剥夺法。挂起某些死锁进程,并抢占它的资源,将这些资源分配给其他的死锁进程。但应防止被挂起的进程长时间得不到资源,而处于资源匮乏的状态。
2) 撤销进程法。强制撤销部分、甚至全部死锁进程并剥夺这些进程的资源。撤销的原则可以按进程优先级和撤销进程代价的高低进行。
3) 进程回退法。让一(多)个进程回退到足以回避死锁的地步,进程回退时自愿释放资源而不是被剥夺。要求系统保持进程的历史信息,设置还原点。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

死锁,死锁的四个必要条件以及处理策略 的相关文章

  • msgId与offsetMsgId区别与rocketmqConsole支持的坑

    背景 在测试环境的一台机子上启动了多个mq实例 xff0c 某一天同事说投递到test环境的数据 xff0c 可以在test4环境上查到 xff0c 这让人有点担心 xff0c 担心投递的数据会被别的消费 经过了解 xff0c 同事提供相关
  • webpack使用和踩过的坑

    使用process argv 获取命令行使用的参数 span class hljs comment 判断是否带production参数 xff0c production会压缩js span span class hljs keyword v
  • DOCKER权限设置:LINUX新增用户添加ROOT权限

    一 首先在LINUX下创建新用户 创建用户username adduser username 修改用户username的密码 passwd username 二 为用户添加ROOT权限 方法一 xff1a 修改 etc sudoers 文件
  • 安卓开发后台3

    1 开发步骤 xff1a 创建一个后台运行的服务启动应用的时候启动服务在onCreate 调用的时候 创建一个系统的服务 并获取电话的状态 span class token variable TelephonyManagermanager
  • putty + Xming windows 远程连接、打开Linux图形界面

    putty 43 Xming windows 远程连接 打开Linux图形界面 由于我是windows端的 xff0c 连接同事的Ubuntu xff0c 所以Linux那端的配置我不是太了解 xff0c 网上应该有相关教程 xff0c 我
  • Docker (二)【镜像拉取】

    二 安装镜像 2 1 安装Nginx span class token comment 搜索Nginx span span class token function docker span search nginx span class t
  • PX4学习笔记之uorb

    PX4学习笔记之uorb 添加topic以及消息的发布 订阅 说明 添加自定义 topic xff0c 简单例子实现new topic 的publish和subscribe 平台 Pixhawk PX4原生固件Firmware 要求 学会p
  • 使用python 启动一个web服务

    背景 xff0c 有一台不能直连的服务器 xff0c 网络是通的 xff0c 需要向服务器上面传文件 xff0c 通过http是最简单的方式 之前使用 anywhere xff0c 但是nodejs安装对于一般人还有一些难度 使用 pyth
  • 启动zookeeper问题排查方式

    测试zookeeper集群搭建时 xff0c 虽然启动结果显示了 STARTED xff0c 但是实际上zookeeper服务并没有启动 xff0c 如下 xff1a span class token punctuation span ro
  • ubuntu 20.04 远程桌面(win10 控制 Ubuntu 20.04)

    参照这篇 https blog csdn net lucky7213 article details 107008246 Windows端注意点 xff1a 启动远程桌面连接 开始菜单中可以找到 xff0c 找不到搜索一下 xff0c 输入
  • FreeRTOS 列表和列表项

    列表 List t gt uxNumberOfItems 列表项个数 gt pxIndex 当前列表项指针 gt xListEnd 列表的尾节点 迷你列表项 struct xMINI LIST ITEM gt xItemValue 列表项值
  • 1、AUTOSAR简介

    AUTOSAR xff08 AUTotmotive Open System ARchitecture xff09 汽车开放系统架构是由全球各大汽车整车厂 汽车零部件供应商 汽车电子软件系统公司联合建立的一套标准协议 xff0c 是对汽车技术
  • Antd4之form表单数据回显

    文章目录 一 函数中设置数据回显 xff0c 使用useForm xff08 1 xff09 使用useForm xff08 2 xff09 在form表单中定义form 二 不使用useForm antd4摒弃了antd3的 getFie
  • Antd之实现form label文字左/右对齐

    文章目录 一 设置文字以冒号分割右对齐二 设置文字以冒号分割左对齐 一 设置文字以冒号分割右对齐 类似下面这种情况 代码 xff1a span class token keyword const span formItemLayout sp
  • AntdPro上传文件之Antd各个版本的对比

    文章目录 一 antd3上传图片二 antd4上传文件三 使用antdPro 之前一直在使用antd上传文件 xff0c 图片 xff0c 从antd3到antd4再到antdPro xff0c 总结一下经验吧 一 antd3上传图片 这里
  • 详解cors跨域

    文章目录 同源策略cors基本概念cors跨域方式简单请求 simple request非简单请求 预检请求 CORS兼容情况CORS总结 同源策略 在以前的一篇博客中有介绍 xff0c 同源策略是一种安全机制 xff0c 为了预防某些恶意
  • 详解flex布局

    文章目录 一 flex布局是什么 xff1f 二 基本概念flex 容器 三 容器的属性1 flex direction属性决定主轴的方向 xff08 即项目的排列方向 xff09 2 flex wrap属性定义如果一条轴线排不下 xff0

随机推荐

  • V4l2框架分析

    Table of Contents 1 V4L2框架概述 1 1 v4l2设备应用层流程 1 2 内核V4L2模块 1 2 1 video device 1 2 2 v4l2 subdev 1 2 3 videobuf2 2 video d
  • 消息中间件-选型

    消息中间件 选型 目录 1 消息中间件作用 1 1 限流削峰 1 2 异步解耦 1 3 数据收集 2 同类产品对比选型 2 1 ActiveMQ 2 2 RabbitMQ 2 3 Kafka 2 4 RocketMQ 1 消息中间件作用 设
  • c 使用mkdir()函数创建路径

    参考代码 xff1a span class hljs preprocessor include lt sys stat h gt span span class hljs preprocessor include lt iostream g
  • 嵌入式软件工程师是干啥的?

    文章目录 前言 一 啥是软件 xff1f 二 什么是嵌入式软件 三 嵌入式软件如何开发 三 嵌入式软件工程师知识技能 编程语言知识 xff1a 自动控制知识 xff1a 硬件基础知识 xff1a 开发工具使用 xff1a 软件架构设计 xf
  • 玩转四旋翼无人机(传感器)

    IMU 一个典型的IMU包括一个三轴陀螺仪 xff0c 一个三轴加速度计和一个三轴磁力计 首先定义惯性坐标系 A xff0c 机体坐标系 B 陀螺仪 陀螺仪测量 B 相对于 A 的角速度 I M U 61 43 b 43
  • 玩转四旋翼无人机(pixhawk飞控校准)

    本文章主要介绍pixhawk的校准过程及其注意事项 step 1 mount 飞控的安装方法 标准方向 飞控板上边的白箭头应该指向飞机的前方 xff0c 飞控大致位于机身的重心 xff08 不论是水平方向还是竖直方向 xff09 xff0c
  • 稠密建图及voxblox

    论文理解 基础简介 地图的表达方式中 一种是occupancy网格地图 其中比较常用的是八叉树地图octomap 它使用分层的八叉树结构存储占据 occupancy 的概率大小 然而很多情况下 仅仅得到occupancy的概率大小是不够的
  • 三维机械加工软件--三维弯管机仿真系统

    整个系统采用vc6 0 43 opengl 干涉部分采用AABB以及OBB算法 可以实现弯管动作仿仿真以及弯管真以及干涉判断 同时集成ybc管型预览ybc编程以及三维管型数据导入 机格式导入 xff0c 并进行配置 采用常用的wrl床模型
  • 网络通信1—TCP程序编写步骤(参照 Ubuntu 16.04 版本)

    TCP基础模型 服务器流程 step 1 xff1a 创建 socke 套接字接口并判断 listenfd 61 socket xff08 AF INET SOCK STREAM 0 xff09 if listenfd 61 61 1 pe
  • 算法实现题:3-9 租用游艇问题

    算法实现题 xff1a 3 9 租用游艇问题 题目略 这个一个可用 DP 求解的问题 N 个游艇出租站 xff0c 不妨从出发到终点分别编号 0 xff0c 2 xff0c N 1 而且每两个站的租金都是不一样的 xff0c 我们用 r x
  • 開始在csdn上寫blog

    哈哈 現在開始寫些技術性的文字啦
  • 廣州亞運會項目維護?!

    今天要搞什麽亞運會的項目維護 xff0c 計算機學院需要招收一些精英 唉 xff01 他們就是好 xff01 有這麼多的機會 xff0c 我們這邊呢 xff01 看來學院老師一點都不關心我們的將來就業情況 我就鬱悶了 難道我們註定是這樣的嗎
  • 从高考到程序员,一生无悔的选择,码农的成长之路

    高考毕业了 xff0c 学弟学妹们哈皮了 但是我身为程序员还在为追梦而努力着 会想高考 xff0c 仿佛就是一场梦 xff0c 一场我无法都无法忘记的梦 高中三年的时光 xff0c 对于我来说是痛苦的 xff0c 我现在极其后悔高中三年的生
  • 安卓Android开发:使用AudioRecord录音、将录音保存为wav文件、使用AudioTrack保存录音

    一 使用AudioRrecord录音 1 1声明 首先需要声明一个AudioRecord类的实例 之所以需要事先声明 xff0c 是因为在本例中 xff0c 录音的启动和结束被封装在两个不同的方法里 而通常来讲 xff0c 开始录音 和 结
  • 最新phpstorm2018.1.4搭建php环境(phpstudy2018)

    最新版phpstorm2018 1 4配置php环境 phpstudy2018 1 下载phpstorm2018 1 4 xff0c 官网下载地址 xff1a https www jetbrains com phpstorm downloa
  • 利用HSV颜色空间和形态学两种思路进行车牌区域的提取

    车牌号的提取首先需要定位车牌区域 本文用HSV颜色空间和形态学两种思路实现对车牌区域的定位 一 利用HSV颜色空间提取车牌区域 利用HSV颜色空间提取车牌区域的思路如下 xff1a 求原图像的sobel边缘 因为普通民用小型车都是蓝底的车牌
  • RT-Thread学习笔记 --(5)RT-Thread线程间同步学习总结

    RT Thread线程间同步学习总结 多线程之间同步是继多线程学习之后 xff0c 需要重点掌握的又一个重要内容 一个实时操作系统里面 xff0c 如果只有多线程而没有线程间同步 xff0c 各个线程都无序运行 xff0c 那么必然会导致整
  • PX4读取串口消息,并通过MAVLINK发送给地面站

    参考 xff1a 131条消息 PX4飞控读取UART串口信息通过Mavlink传给QGC地面站显示 XXX UUU XXX的博客 CSDN博客 px4串口2 PX4版本 xff1a 1 12 1 3 QGC版本 4 2 0 Ubuntu版
  • Ubuntu 20.04.4配制pPX4开发环境

    PX4官方指南 Ubuntu Development Environment PX4 User Guide 一 从PX4的官方给github拉取代码 1 进入主目录 xff0c 进入到你要存PX4的文件夹 我这里是创建了一个px4的文件夹
  • 死锁,死锁的四个必要条件以及处理策略

    一 什么是死锁二 死锁与饥饿三 资源的类型 3 1 可重用资源和消耗性资源 3 1 1 可重用资源 xff08 永久性资源 xff09 3 1 2 消耗性资源 xff08 临时性资源 xff09 3 2 可抢占资源和不可抢占资源 3 2 1