COM原理与实现之二: 聚合

C++没有同聚合等价的特性。聚合实际上是继承性的一种动态形式。而C++的继承总是静态的,是实现继承。COM是接口继承,通过聚合接口,可以做成动态配置。

研究COM,主要是利用接口继承的灵活性构筑强大的系统:可配置、可插拔、可脚本化。本文不讲太多理论,详细原理参考[COM技术内幕]这本书。关于[COM技术内幕],很多内容过时了,比如注册表,类厂之类的。我更关心COM思想所蕴含的哲学。我实现了跨平台COM,支持聚合。

GameStencil这个组件聚合了SystemMngmt这个组件。最初采用IGameStencil::getSystemMngmt()这样的形式返回一个ISystemMngmt接口指针,显然这不是聚合。通过A对象的方法得到B对象,显然A仅仅是B的一种类厂。于是我下决心解决组件聚合问题。就有了本文。

core目录下面就3个文件,是我的跨平台COM的基础。

1) Platform.h

/**
* Platform.h
*
*
* Init Created: 2016-06-10
* Last Updated: 2016-06-10
*/
#ifndef PLATFORM_H
#define PLATFORM_H

#if defined _MSC_VER || WIN32
    #ifndef OS_PLATFORM_WIN
        #define OS_PLATFORM_WIN
    #endif
#endif

#ifdef OS_PLATFORM_WIN
    #include <windows.h>
    #include <process.h>
#else
    #include <pthread.h>
    #include <unistd.h>
#endif

#ifndef interface
#define interface struct
#endif

/**
* interface iid
*/
typedef unsigned int iid_t;

/**
* long result
*/
typedef long lresult_t;

#define lres_success             0
#define lres_error             (-1)
#define lres_e_initdata        (-2)
#define lres_e_outmemory       (-4)
#define lres_e_nointerface     (-11)
#define lres_e_noaggregation   (-12)

/**
* thread_ctx
*/
#define thread_ctx_single    0
#define thread_ctx_multiple  1

/**
* ref count type
*/
#ifdef OS_PLATFORM_WIN
    typedef volatile unsigned long refcount_t;
    #define __interlock_inc(add)  InterlockedIncrement(add)
    #define __interlock_dec(sub)  InterlockedDecrement(sub)
#else
    typedef volatile size_t refcount_t;
    #define __interlock_inc(add)  __sync_add_and_fetch(add, 1)
    #define __interlock_dec(sub)  __sync_sub_and_fetch(sub, 1)
#endif

#endif /* PLATFORM_H */

2) Universal.h

/**
* Universal.h
*
* Refer:
*   <<Inside COM>>
*
* Init Created: 2016-06-10
* Last Updated: 2016-06-13
*/
#ifndef UNIVERSAL_H
#define UNIVERSAL_H

#include "Platform.h"

// IUniversal is a variant from IUnknown
//
interface IUniversal
{
    static const iid_t IID = ((iid_t) (0));

    virtual lresult_t query(iid_t iid, void **ppvOut) = 0;
    virtual unsigned long retain(void) = 0;
    virtual unsigned long release(void) = 0;
};

#define iid_IUniversal  (IUniversal::IID)

// Nondelegating IUniversal interface
//   - Nondelegating version of IUniversal
//
interface INondelegatingUniversal
{
    static const iid_t IID = ((iid_t) (-1));

    virtual lresult_t NondelegatingQuery(iid_t iid, void **ppvOut) = 0;
    virtual unsigned long NondelegatingRetain(void) = 0;
    virtual unsigned long NondelegatingRelease(void) = 0;
};

#define iid_INondelegatingUniversal  (INondelegatingUniversal::IID)

class UniversalImpl
{
private:
    unsigned  thread_ctx;
    refcount_t  ref_count;

public:
    UniversalImpl() :
        ref_count(1),
        thread_ctx(thread_ctx_multiple) {
        printf("UniversalImpl\n");
    }

    virtual ~UniversalImpl() {
        printf("~UniversalImpl\n");
    }

    void init(unsigned threadctx) {
        thread_ctx = threadctx;
    }

    // Notification to derived classes that we are releasing
    void finalRelease() {
        // Increment reference count for final release
        ref_count = 1;
    }

    unsigned getThreadCtx() const {
        return thread_ctx;
    }

    // IUniversal
    //
    virtual lresult_t query(iid_t iid, void **ppv) = 0;

    virtual unsigned long retain(void) {
        if (thread_ctx == thread_ctx_multiple) {
            return __interlock_inc(&ref_count);
        } else {
            return ++ref_count;
        }
    }

    virtual unsigned long release(void) {
        if (thread_ctx == thread_ctx_multiple) {
            if (__interlock_dec(&ref_count) == 0) {
                delete this;
                return 0;
            }
        } else {
            if (--ref_count == 0) {
                delete this;
                return 0;
            }
        }
        return ref_count;
    }
};

// Declaration of NondelegatingUniversalImpl
//   - Base class for implementing INondelegatingUniversal
//
class NondelegatingUniversalImpl : public INondelegatingUniversal
{
public:

    virtual lresult_t NondelegatingQuery(iid_t iid, void **ppv) = 0;

    virtual unsigned long NondelegatingRetain(void) {
        if (thread_ctx == thread_ctx_multiple) {
            return __interlock_inc(&ref_count);
        } else {
            return ++ref_count;
        }
    }

    virtual unsigned long NondelegatingRelease(void) {
        if (thread_ctx == thread_ctx_multiple) {
            if (__interlock_dec(&ref_count) == 0) {
                delete this;
                return 0;
            }
        } else {
            if (--ref_count == 0) {
                delete this;
                return 0;
            }
        }
        return ref_count;
    }

    // Constructor
    NondelegatingUniversalImpl(IUniversal* pUniversalOuter) :
            ref_count(1) {
        // Set outer_universal pointer
        if (! pUniversalOuter) {
            // Not aggregating; delegate to nondelegating IUniversal
            m_pUniversalOuter = reinterpret_cast<IUniversal*>
                (static_cast<INondelegatingUniversal*>
                (this));
        } else {
            // Aggregating; delegate to outer IUniversal
            m_pUniversalOuter = pUniversalOuter;
        }
    }

    // Destructor
    virtual ~NondelegatingUniversalImpl() {
    }

    // Initialization (especially for aggregates)
    void init(unsigned threadctx) {
        thread_ctx = threadctx;
    }

    // Notification to derived classes that we are releasing
    virtual void finalRelease() {
        // Increment reference count for final release
        ref_count = 1;
    }

protected:
    // Support for delegation
    IUniversal* getUniversalOuter() const {
        return m_pUniversalOuter;
    }

private:
    // thread context
    unsigned thread_ctx;

    // Reference count for this object
    refcount_t  ref_count;

    // Pointer to (external) outer IUniversal
    IUniversal* m_pUniversalOuter;
};

///////////////////////////////////////////////////////////
//
// Delegating IUniversal
//   - Delegates to the nondelegating IUniversal, or to the
//      outer IUniversal if the component is aggregated.
//
#define DECLARE_UNIVERSAL_INTERFACE \
    virtual lresult_t query(iid_t iid, void **ppv) { \
        return getUniversalOuter()->query(iid, ppv); \
    } \
    virtual unsigned long retain(void) { \
        return getUniversalOuter()->retain(); \
    } \
    virtual unsigned long release(void) { \
        return getUniversalOuter()->release(); \
    }

#define CREATE_INSTANCE_NO_AGGREGATION(className) \
    static lresult_t createInstance(\
            unsigned threadctx,\
            IUniversal *pUniversalOuter,\
            iid_t iid,\
            void **ppv) {\
        /* cannot be aggregated */ \
        if (pUniversalOuter) {\
            return lres_e_noaggregation; \
        } \
        className * p = new className();\
        if ( ! p) {\
            return lres_e_outmemory;\
        }\
        lresult_t hr = p->init(threadctx);\
        if (hr != lres_success) {\
            p->NondelegatingRelease();\
            return hr;\
        }\
        hr = p->NondelegatingQuery(iid, ppv);\
        p->NondelegatingRelease();\
        return hr;\
    }

#define CREATE_INSTANCE_WITH_AGGREGATION(className) \
    static lresult_t createInstance(\
            unsigned threadctx,\
            IUniversal* pUniversalOuter,\
            iid_t iid,\
            void **ppv) {\
        className * p = new className(pUniversalOuter);\
        if ( ! p) {\
            return lres_e_outmemory;\
        }\
        lresult_t hr = p->init(threadctx);\
        if (hr != lres_success) {\
            p->release();\
            return hr;\
        }\
        hr = p->NondelegatingQuery(iid, ppv);\
        p->NondelegatingRelease();\
        return hr;\
    }

#endif /* UNIVERSAL_H */

3)SIPtr.h

/**
* SIPtr.h
*    Smart Interface Pointer
*
* Use: SIPtr<IX> spIX;
*     Do not use with IUniversal; SIPtr<IUniversal>
*       will not compile.  Instead, use IUniversalPtr.
*
* Refer:
*   <<Inside COM>>
*
* Init Created: 2016-06-10
* Last Updated: 2016-06-10
*/
#ifndef SIPTR_H
#define SIPTR_H

#include "Universal.h"

#include <assert.h>

template <class T> class SIPtr
{
public:

    // Constructors
    SIPtr() {
        m_pI = 0;
    }

    SIPtr(T* lp) {
        m_pI = lp;
        if ( m_pI ) {
            m_pI->retain();
        }
    }

    SIPtr(IUniversal* pI) {
        m_pI = 0;
        if ( pI ) {
            pI->query(T::IID, (void **) & m_pI);
        }
    }

    // Destructor
    ~SIPtr() {
        release();
    }

    // Reset
    void release() {
        if ( m_pI ) {
            T* pOld = m_pI;
            m_pI = 0;
            pOld->release();
        }
    }

    // Attach to an existing interface (does not retain)
    void attach(T * pI) {
        if (m_pI != pI) {
            IUniversal* pOld = m_pI;

            m_pI = pI;

            if (pOld) {
                // Release the old interface
                pOld->release();
            }
        }
    }

    // Detach the interface (does not release)
    T* detach() {
        T* pOld = m_pI;
        m_pI = 0;
        return pOld;
    }

    T* get() {
        return m_pI;
    }

    // Conversion
    operator T*() {
        return m_pI;
    }

    // Pointer operations
    T& operator*() {
        assert(m_pI);
        return * m_pI;
    }

    T** operator&() {
        assert(!m_pI);
        return &m_pI;
    }

    T* operator->() {
        assert(m_pI);
        return m_pI;
    }

    // Assignment from the same interface
    T* operator=(T* pI) {
        if (m_pI != pI) {
            // Save current value
            IUniversal* pOld = (IUniversal *) m_pI;

            // Assign new value
            m_pI = pI;

            if (m_pI) {
                m_pI->retain();
            }

            if (pOld) {
                // Release the old interface
                pOld->release();
            }
        }
        return m_pI;
    }

    // Assignment from another interface
    T* operator=(IUniversal* pI) {
        // Save current value
        IUniversal* pOld = m_pI;
        m_pI = 0;

        // Query for correct interface
        if ( pI ) {
            lresult_t hr = pI->query(T::iid_interface, (void**) & m_pI);
            assert(hr == lres_success && m_pI);
        }

        if ( pOld ) {
            // Release old pointer
            pOld->release();
        }
        return m_pI ;
    } 

    // bool functions
    bool operator!() {
        return m_pI ? false : true;
    }

    // Requires a compiler that supports BOOL
    operator bool() const {
        return m_pI ? true : false;
    }

    // Interface ID
    iid_t iid() {
        return T::IID;
    } 

private:
    // Pointer variable
    T* m_pI;
};

/**
* IUniversalPtr is a smart interface for IUniversal
*/
class IUniversalPtr
{
public:
    // Constructors
    IUniversalPtr() {
        m_pI = 0;
    }

    IUniversalPtr(IUniversal* lp) {
        m_pI = lp;
        if ( m_pI ) {
            m_pI->retain();
        }
    }

    // Destructor
    ~IUniversalPtr() {
        release();
    }

    // Reset
    void release() {
        if (m_pI) {
            IUniversal* pOld = m_pI;
            m_pI = 0;
            pOld->release();
        }
    }

    // Conversion
    operator IUniversal*() {
        return (IUniversal*) m_pI;
    }

    // Pointer operations
    IUniversal& operator*() {
        assert(m_pI);
        return *m_pI;
    }

    IUniversal** operator&() {
        assert(!m_pI);
        return &m_pI;
    }

    IUniversal* operator->() {
        assert(m_pI);
        return m_pI;
    }

    // Assignment
    IUniversal* operator=(IUniversal* pI) {
        if (m_pI != pI) {
            // Save current value
            IUniversal* pOld = m_pI;

            // Assign new value
            m_pI = pI;

            if ( m_pI ) {
                m_pI->retain();
            }

            if ( pOld ) {
                // Release the old interface
                pOld->release();
            }
        }
        return m_pI;
    }

    // Boolean functions
    bool operator!() {
        return m_pI ? false : true;
    }

    operator bool() const {
        return m_pI ? true : false;
    }

private:
    // Pointer variable
    IUniversal* m_pI;
}; 

#endif /* SIPTR_H */

组件 GameStencil的代码:

/**
* IGameStencil.h
*
* Author: master@pepstack.com
*
* Refer:
*   http://www.richardlord.net/blog/what-is-an-entity-framework
*   http://blog.csdn.net/i_dovelemon/article/details/30250049
*   http://blog.csdn.net/zhao_92221/article/details/46629553
*   http://blog.csdn.net/ubuntu64fan/article/details/8839778
*
* Init Created: 2016-06-13
* Last Updated: 2016-06-13
*/
#ifndef IGAME_STENCIL_H
#define IGAME_STENCIL_H

#include "core/SIPtr.h"

namespace ecs {

interface IGameStencil : IUniversal {
    static const iid_t IID = ((iid_t) 0x00F000);

    virtual void update(float dt) = 0;
};

}; /* namespace ecs */

#endif /* IGAME_STENCIL_H */

/**
* GameStencil.h
*   The GameStencil class is the central point for creating
*     and managing your game state.
*
* Refer:
*   http://www.richardlord.net/blog/what-is-an-entity-framework
*   http://blog.csdn.net/i_dovelemon/article/details/30250049
*   http://blog.csdn.net/zhao_92221/article/details/46629553
*   http://blog.csdn.net/ubuntu64fan/article/details/8839778
*
* Init Created: 2016-06-12
* Last Updated: 2016-06-12
*/
#ifndef GAME_STENCIL_H
#define GAME_STENCIL_H

#include "IGameStencil.h"

#include "SystemMngmt.h"

#include <memory>
#include <vector>
using namespace std;

namespace ecs {

class GameStencil :
    public IGameStencil,
    public NondelegatingUniversalImpl
{
public:
    // Creation
    //
    CREATE_INSTANCE_NO_AGGREGATION(GameStencil)

private:

    // Constructor
    GameStencil() :
        NondelegatingUniversalImpl(0),
        updating(false),
        m_pUniversalInner(0) {

        printf("GameStencil\n");

        m_pISystemMngmt = 0;
    }

    // Destructor
    virtual ~GameStencil() {
        finalRelease();

        printf("~GameStencil\n");
    }

	// Initialization
    //
	virtual lresult_t init(unsigned threadctx) {
        NondelegatingUniversalImpl::init(threadctx);

        IUniversal * pUniversalOuter = this;

        lresult_t hr = SystemMngmt::createInstance(threadctx, pUniversalOuter,
            IUniversal::IID, (void**) &m_pUniversalInner);

        if (hr != lres_success) {
            return lres_error;
        }

        hr = m_pUniversalInner->query(ISystemMngmt::IID, (void**) &m_pISystemMngmt);

        if (hr != lres_success) {
            m_pUniversalInner->release();
            return lres_error;
        }

        pUniversalOuter->release();
        return lres_success;
    }

    virtual void finalRelease() {
        NondelegatingUniversalImpl::finalRelease();

        getUniversalOuter()->retain();

        m_pISystemMngmt->release();

        if (m_pUniversalInner) {
            m_pUniversalInner->release();
        }
    }

    // IUniversal
    //
    DECLARE_UNIVERSAL_INTERFACE

    // INondelegatingUniversal
    //
	virtual lresult_t NondelegatingQuery(iid_t iid, void** ppv) {
        if (iid == IUniversal::IID) {
            *ppv = static_cast<IGameStencil*> (this);
        } else if (iid == IGameStencil::IID) {
            *ppv = static_cast<IGameStencil*> (this);
        } else if (iid == ISystemMngmt::IID) {
            // contained component
            *ppv = m_pISystemMngmt;
        } else {
            *ppv = 0;
            return lres_e_nointerface;
        }

        reinterpret_cast<IUniversal*> (*ppv)->retain();
        return lres_success;
    }

    // IGameStencil
    //
    virtual void update(float dt) {
        updating = true;

        // TODO:

        updating = false;
    }

private:
    bool updating;

    IUniversal * m_pUniversalInner;

    ISystemMngmt * m_pISystemMngmt;
};

}; /* namespace ecs */

#endif /* GAME_STENCIL_H */

被聚合的组件 SystemMngmt的代码:

/**
* ISystemMngmt.h
*
* Author: master@pepstack.com
*
* Refer:
*   http://www.richardlord.net/blog/what-is-an-entity-framework
*   http://blog.csdn.net/i_dovelemon/article/details/30250049
*   http://blog.csdn.net/zhao_92221/article/details/46629553
*   http://blog.csdn.net/ubuntu64fan/article/details/8839778
*
* Init Created: 2016-06-10
* Last Updated: 2016-06-12
*/
#ifndef ISYSTEM_MNGMT_H
#define ISYSTEM_MNGMT_H

#include "core/SIPtr.h"

namespace ecs {

interface ISystemMngmt : IUniversal
{
    static const iid_t IID = ((iid_t) 0x10F001);

    virtual void update(float dt) = 0;
    virtual void pause() = 0;
    virtual void resume() = 0;
};

}; /* namespace ecs */

#endif /* ISYSTEM_MNGMT_H */

/**
* SystemMngmt.h
*
* Refer:
*   http://www.richardlord.net/blog/what-is-an-entity-framework
*   http://blog.csdn.net/i_dovelemon/article/details/30250049
*   http://blog.csdn.net/zhao_92221/article/details/46629553
*   http://blog.csdn.net/ubuntu64fan/article/details/8839778
*
* Init Created: 2016-06-13
* Last Updated: 2016-06-13
*/
#ifndef SYSTEM_MNGMT_H
#define SYSTEM_MNGMT_H

#include "ISystemMngmt.h"

#include <memory>
#include <vector>
using namespace std;

namespace ecs {

class SystemMngmt :
    public ISystemMngmt,
    public NondelegatingUniversalImpl
{
public:
    // Creation
    //
	CREATE_INSTANCE_WITH_AGGREGATION(SystemMngmt)

private:

	// Constructor
    SystemMngmt(IUniversal * pUniversalOuter) :
        NondelegatingUniversalImpl(pUniversalOuter) {
        paused = false;
        printf("SystemMngmt\n");
    }

    // Destructor
    virtual ~SystemMngmt() {
        finalRelease();
        printf("~SystemMngmt\n");
    }

    virtual lresult_t init(unsigned threadctx) {
        NondelegatingUniversalImpl::init(threadctx);
        return lres_success;
    }

public:

    // IUniversal
    //
    DECLARE_UNIVERSAL_INTERFACE

    // INondelegatingUniversal
    //
	virtual lresult_t NondelegatingQuery(iid_t iid, void** ppv) {
        if (iid == IUniversal::IID) {
            *ppv = static_cast<INondelegatingUniversal*> (this);
        } else if (iid == ISystemMngmt::IID) {
            *ppv = static_cast<ISystemMngmt*> (this);
        } else {
            *ppv = 0;
            return lres_e_nointerface;
        }
        reinterpret_cast<IUniversal*> (*ppv)->retain();
        return lres_success;
    }

    // ISystemMngmt
    //

    // Update all the system
    void update(float dt) {

    }

    // Pause all the systems
    void pause() {
        paused = true;
    }

    // Resume all the systems
    void resume() {
        paused = false;
    }

private:

    bool paused;
};

}; /* namespace ecs */

#endif /* SYSTEM_MNGMT_H */

最后是测试代码:

//
// main.cpp
//
#ifdef WIN32
    // Refer:
    //   http ://www.cnblogs.com/skynet/archive/2011/02/20/1959162.html
    #define _CRTDBG_MAP_ALLOC
    #include <stdlib.h>
    #include <crtdbg.h>
#else
    #include <stdlib.h>
#endif

#include <assert.h>
#include <stdio.h>
#include <string.h>

#include "model/GameStencil.h"

using namespace ecs;

void usage()
{
    SIPtr<IGameStencil> spGame;
    GameStencil::createInstance(thread_ctx_single, 0, spGame.iid(), (void**) &spGame);

    SIPtr<ISystemMngmt> spSysMngmt;
    spGame->query(spSysMngmt.iid(), (void**) &spSysMngmt);

    SIPtr<IGameStencil> spGame2;
    spSysMngmt->query(spGame2.iid(), (void**) &spGame2);

    assert(spGame2.get() == spGame.get());

    spSysMngmt->update(0.1f);
}

int main()
{
#ifdef _CRTDBG_MAP_ALLOC
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif

    printf("main.cpp start\n");

    usage();

    printf("main.cpp exit.\n");
    return 0;
}

没有内存泄露。OK!

COM原理与实现之二: 聚合的更多相关文章

  1. SSH原理与运用(二):远程操作与端口转发

    SSH原理与运用(二):远程操作与端口转发 作者:阮一峰 (Image credit: Tony Narlock) 七.远程操作 SSH不仅可以用于远程主机登录,还可以直接在远程主机上执行操作. 上一 ...

  2. JVM工作原理和特点(一些二逼的逼神面试官会问的问题)

    作为一种阅读的方式了解下jvm的工作原理 ps:(一些二逼的逼神面试官会问的问题) JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.exe来完毕,通过以下4步来完毕JVM环境. ...

  3. kafka原理和实践(二)spring-kafka简单实践

    系列目录 kafka原理和实践(一)原理:10分钟入门 kafka原理和实践(二)spring-kafka简单实践 kafka原理和实践(三)spring-kafka生产者源码 kafka原理和实践( ...

  4. 从底层谈WebGIS 原理设计与实现(二):探究本质,WebGIS前端地图显示之地图比例尺换算原理

    从底层谈WebGIS 原理设计与实现(二):探究本质,WebGIS前端地图显示之地图比例尺换算原理 作者:naaoveGI…    文章来源:http://www.cnblogs.com/naaove ...

  5. [转帖]SSH原理与运用(二):远程操作与端口转发

    SSH原理与运用(二):远程操作与端口转发 http://www.ruanyifeng.com/blog/2011/12/ssh_port_forwarding.html 接着前一次的文章,继续介绍S ...

  6. RabbitMQ原理与相关操作(二)

    接着 上篇随笔 增加几个概念: RabbitMQ是一个在AMQP(高级消息队列协议)标准基础上完整的,可服用的企业消息系统. AMQP模型的功能组件图(上图摘自 Sophia_tj 的 第2章 AMQ ...

  7. Spring Boot自动配置原理与实践(二)

    前言 在之前的博文(Spring Boot自动配置原理与实践(一))中,已经介绍了Spring boot的自动配置的相关原理与概念,本篇主要是对自动配置的实践,即自定义Starter,对原理与概念加深 ...

  8. angr原理与实践(二)—— 各类图的生成(CFG CG ACFG DDG等)

    ​  本文系原创,转载请说明出处 Please Subscribe Wechat Official Account:信安科研人,获取更多的原创安全资讯 上一篇文章介绍了angr的原理,自此篇文章开始, ...

  9. Web程序的运行原理及流程(二)

    其实WEB服务器和WEB应用服务器这两个概念特别容易混淆  可以理解为装了不同软件(服务)的两台计算机(服务器)吧 先对两个概念做一个简单介绍 了解了基本的概念 我们再用两个典型的例子做一下比较(建立 ...

随机推荐

  1. Go学习——go+channel实战(转)

    转载:http://studygolang.com/articles/2423 背景 在最近开发的项目中,后端需要编写许多提供HTTP接口的API,另外技术选型相对宽松,因此选择Golang + Be ...

  2. UVALive - 3942:Remember the Word

    发现字典里面的单词数目多且长度短,可以用字典树保存 f[i]表示s[i~L]的分割方式,则有f[i]=∑f[i+len(word[j])]   其中word[j]为s[i~L]的前缀 注意字典树又叫前 ...

  3. 计蒜客NOIP2017提高组模拟赛(三)day1

    火山喷发 火山喷发对所有附近的生物具有毁灭性的影响.在本题中,我们希望用数值来模拟这一过程. 在环境里有 n 个生物分别具有 A​1​​,A​2​​,⋯,A​n​​点生命值,一次火山喷发总计 MM 轮 ...

  4. java实现生产者/消费者的三种方式

    package com.wenki.thread; import java.util.LinkedList; import java.util.concurrent.LinkedBlockingQue ...

  5. 解决win10 VC++6.0 应用程序无法正常运行 0xc0000142

    废话不多说,无法正常运行原因就是win10不兼容中文版的vc,解决方法就是一句话,用英文版的msdev.exe替换中文版的msdev.exe,msdev.exe是vc的启动程序.直接上来教你怎么做.废 ...

  6. C语言程序设计第六次作业--循环结构(2)

    (一)改错题 序列求和:输入一个正实数eps,计算序列部分和 1 - 1/4 + 1/7 - 1/10 + ... ,精确到最后一项的绝对值小于eps(保留6位小数). 输入输出样例: Input e ...

  7. Ambari2.6.0 安装HDP2.6.3(离线安装)

    一.下载安装包 因为使用在线安装特别慢,所有的安装包加起来有9个G左右,所以本教程是通过迅雷下载包,然后上传到服务器,通过配置本地源的方式来实现的离线安装.通过ambari安装需要下载下面的三个主要包 ...

  8. 值得珍藏的HTTP协议详解

    转自:http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html 引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式 ...

  9. UI相关

    前端 UI 框架 https://github.com/twbs/bootstrap https://github.com/google/material-design-lite https://gi ...

  10. ACM 畅通工程

    Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府"畅通工程"的目标是使全省任何两个城镇间都可以实现交通 ...