API initialization and cleanup

Discussion in 'C++' started by Mark Stijnman, Nov 24, 2005.

  1. I need to use an API in our current project and I have been writing
    some wrapper classes for the functionality we need. Unfortunately,
    before you can use any API calls, the API must be initialized, and
    after your done with the API, it wants you to call a cleanup function.
    I am now looking for a safe solution to wrap the API
    initialization/cleanup.

    I am thinking of something along these lines: every class that needs
    the API is privately inherited from a class like this one:

    class ApiUser {
    public:
    ApiUser() {
    if (_count==0) API_Init();
    _count++;
    }
    ApiUser(ApiUser& a) {
    _count++;
    }
    ~ApiUser() {
    _count--;
    if (_count==0) API_Cleanup();
    }
    private:
    static unsigned int _count;
    };

    // In cpp file:
    int ApiUser::_count = 0;

    So, if class A uses the Api, I would declare

    class A: private ApiUser { ... };

    Would this be a good solution? The static count variable makes me a
    little uncomfortable, especially since I expect that threads will be
    used at some point. I could of course use mutexes/locks on the static
    variable. Are there any other drawbacks I'm missing?

    Are there any other approaches that can be used? I've tried looking for
    them, but haven't been able to find it, despite the fact that this must
    be a rather commonly occurring thing. How have you solved this? Thanks
    for any comments or pointers,

    regards Mark
     
    Mark Stijnman, Nov 24, 2005
    #1
    1. Advertising

  2. Mark Stijnman

    Ben Pope Guest

    Mark Stijnman wrote:
    > I need to use an API in our current project and I have been writing
    > some wrapper classes for the functionality we need. Unfortunately,
    > before you can use any API calls, the API must be initialized, and
    > after your done with the API, it wants you to call a cleanup function.
    > I am now looking for a safe solution to wrap the API
    > initialization/cleanup.
    >
    > I am thinking of something along these lines: every class that needs
    > the API is privately inherited from a class like this one:
    >
    > class ApiUser {
    > public:
    > ApiUser() {
    > if (_count==0) API_Init();
    > _count++;
    > }
    > ApiUser(ApiUser& a) {
    > _count++;
    > }
    > ~ApiUser() {
    > _count--;
    > if (_count==0) API_Cleanup();
    > }
    > private:
    > static unsigned int _count;
    > };
    >
    > // In cpp file:
    > int ApiUser::_count = 0;
    >
    > So, if class A uses the Api, I would declare
    >
    > class A: private ApiUser { ... };
    >
    > Would this be a good solution? The static count variable makes me a
    > little uncomfortable, especially since I expect that threads will be
    > used at some point. I could of course use mutexes/locks on the static
    > variable. Are there any other drawbacks I'm missing?


    Thats horrible, what if a free function needs to use the API?

    > Are there any other approaches that can be used? I've tried looking for
    > them, but haven't been able to find it, despite the fact that this must
    > be a rather commonly occurring thing. How have you solved this? Thanks
    > for any comments or pointers,


    Whats wrong with:

    class ApiWrapper {
    ApiWrapper() {API_Init();}
    ~ApiWrapper() {API_Cleanup();}
    }

    int main() {
    // Anything not using API.
    ApiWrapper apiWrapper;
    // Anything using API.
    // Cleanup automatic when the temporary is destroyed.
    }

    Unless it's particularly expensive to initialise and you might not need
    it in the programs lifetime.

    Ben Pope.
     
    Ben Pope, Nov 24, 2005
    #2
    1. Advertising

  3. Ben Pope wrote:

    > Thats horrible, what if a free function needs to use the API?
    >


    One could use a local variable in the free function like so:

    void ApiUsingFunc() {
    ApiUser localApiUser;
    // Do Api stuff
    }

    >
    > Whats wrong with:
    >
    > class ApiWrapper {
    > ApiWrapper() {API_Init();}
    > ~ApiWrapper() {API_Cleanup();}
    > }
    >
    > int main() {
    > // Anything not using API.
    > ApiWrapper apiWrapper;
    > // Anything using API.
    > // Cleanup automatic when the temporary is destroyed.
    > }
    >
    > Unless it's particularly expensive to initialise and you might not need
    > it in the programs lifetime.
    >
    > Ben Pope.


    For one thing, having that in the main function makes it more difficult
    to transparently use the other wrapper classes. I kinda like the RIIA
    idiom and I would if anyway possible hide the init/cleanup details from
    the user. In your example, the programmer would need to know that
    somewhere in all the components your application uses, the Api is
    needed.

    regards Mark
     
    Mark Stijnman, Nov 24, 2005
    #3
  4. Mark Stijnman wrote:

    > Would this be a good solution?


    It's a good one. Looks somewhat similar to schwarz counter used ti
    initialize iostreams.

    > The static count variable makes me a
    > little uncomfortable, especially since I expect that threads will be
    > used at some point. I could of course use mutexes/locks on the static
    > variable. Are there any other drawbacks I'm missing?


    On many platforms you could use atomic integer ops, such as those from
    <bits/atomicity.h> header shipped with g++.
     
    Maxim Yegorushkin, Nov 24, 2005
    #4
  5. Mark Stijnman

    Ben Pope Guest

    Mark Stijnman wrote:
    > Ben Pope wrote:
    >
    >> Thats horrible, what if a free function needs to use the API?
    >>

    >
    > One could use a local variable in the free function like so:
    >
    > void ApiUsingFunc() {
    > ApiUser localApiUser;
    > // Do Api stuff
    > }
    >
    >> Whats wrong with:
    >>
    >> class ApiWrapper {
    >> ApiWrapper() {API_Init();}
    >> ~ApiWrapper() {API_Cleanup();}
    >> }
    >>
    >> int main() {
    >> // Anything not using API.
    >> ApiWrapper apiWrapper;
    >> // Anything using API.
    >> // Cleanup automatic when the temporary is destroyed.
    >> }
    >>
    >> Unless it's particularly expensive to initialise and you might not need
    >> it in the programs lifetime.
    >>
    >> Ben Pope.

    >
    > For one thing, having that in the main function makes it more difficult
    > to transparently use the other wrapper classes. I kinda like the RIIA
    > idiom and I would if anyway possible hide the init/cleanup details from
    > the user. In your example, the programmer would need to know that
    > somewhere in all the components your application uses, the Api is
    > needed.


    OK, so I think I misunderstood, slightly.

    You're providing an API that uses another API. Your API has several
    classes, and multiple classes require the other API?

    Actually, your example isn't nearly as bad as I thought it might be, I
    thought you expected your users to inherit from the base class.

    I think it's fine, perhaps use a protected destructor if you don't have
    any free functions that require the API.

    Apologies for the misunderstanding!

    Ben Pope
     
    Ben Pope, Nov 24, 2005
    #5
  6. Ben Pope wrote:
    > OK, so I think I misunderstood, slightly.
    >
    > You're providing an API that uses another API. Your API has several
    > classes, and multiple classes require the other API?


    Yeah, that's what's happening, I'm basically wrapping some
    functionality from a C API in some classes, and they need the API to be
    initialized. The cleanup of that API however destroys all open
    resources, so just calling API_Init in each class's ctor and
    API_Cleanup in each dtor won't work.

    > Actually, your example isn't nearly as bad as I thought it might be, I
    > thought you expected your users to inherit from the base class.


    No, only the wrapper classes that I am writing will inherit from
    ApiUser.

    > I think it's fine, perhaps use a protected destructor if you don't have
    > any free functions that require the API.
    >
    > Apologies for the misunderstanding!


    No sweat :) Besides, your comment about free functions was something I
    hadn't thought about, so thanks for pointing that out. I'll probably
    just keep the dtor public, so I can indeed use this for free functions
    too, should the need ever arrive.

    > Ben Pope


    regards Mark
     
    Mark Stijnman, Nov 24, 2005
    #6
  7. Mark Stijnman

    Zara Guest

    On 24 Nov 2005 01:54:32 -0800, "Mark Stijnman"
    <> wrote:

    >I need to use an API in our current project and I have been writing
    >some wrapper classes for the functionality we need. Unfortunately,
    >before you can use any API calls, the API must be initialized, and
    >after your done with the API, it wants you to call a cleanup function.
    >I am now looking for a safe solution to wrap the API
    >initialization/cleanup.
    >
    >I am thinking of something along these lines: every class that needs
    >the API is privately inherited from a class like this one:
    >
    >class ApiUser {
    >public:
    > ApiUser() {
    > if (_count==0) API_Init();
    > _count++;
    > }
    > ApiUser(ApiUser& a) {
    > _count++;
    > }
    > ~ApiUser() {
    > _count--;
    > if (_count==0) API_Cleanup();
    > }
    >private:
    > static unsigned int _count;
    >};
    >
    >// In cpp file:
    >int ApiUser::_count = 0;
    >
    >So, if class A uses the Api, I would declare
    >
    >class A: private ApiUser { ... };
    >
    >Would this be a good solution? The static count variable makes me a
    >little uncomfortable, especially since I expect that threads will be
    >used at some point. I could of course use mutexes/locks on the static
    >variable. Are there any other drawbacks I'm missing?
    >
    >Are there any other approaches that can be used? I've tried looking for
    >them, but haven't been able to find it, despite the fact that this must
    >be a rather commonly occurring thing. How have you solved this? Thanks
    >for any comments or pointers,
    >
    >regards Mark


    This is in fact the usual solution, if you are in a single threaded
    application.
    For mutithreaded applications, I would recommend asking in
    comp.programming.threads.
     
    Zara, Nov 24, 2005
    #7
  8. Mark Stijnman

    Guest

    Mark Stijnman wrote:
    > I need to use an API in our current project and I have been writing
    > some wrapper classes for the functionality we need. Unfortunately,
    > before you can use any API calls, the API must be initialized, and
    > after your done with the API, it wants you to call a cleanup function.


    ( Good single-threaded solution)

    > The static count variable makes me a
    > little uncomfortable, especially since I expect that threads will be
    > used at some point. I could of course use mutexes/locks on the static
    > variable. Are there any other drawbacks I'm missing?


    The library might need per-thread cleanup, and you don't have to
    lockout
    all threads if a thread drops one reference but keeps another. So,
    basically
    i'd do (in pseudo-code)

    if(thread_reference_count == 0) {
    lock mutex
    if( program_reference_count == 0 ) {
    init_api()
    program_reference_count == 1
    } else {
    ++program_reference_count;
    unlock mutex
    thread_reference_count = 1;
    } else
    thread_reference_count += 1;
    }

    You only need the mutex once per thread in this design.

    HTH,
    Michiel Salters
     
    , Nov 24, 2005
    #8
  9. wrote:

    []

    > > The static count variable makes me a
    > > little uncomfortable, especially since I expect that threads will be
    > > used at some point. I could of course use mutexes/locks on the static
    > > variable. Are there any other drawbacks I'm missing?

    >
    > The library might need per-thread cleanup, and you don't have to
    > lockout
    > all threads if a thread drops one reference but keeps another. So,
    > basically
    > i'd do (in pseudo-code)
    >
    > if(thread_reference_count == 0) {
    > lock mutex
    > if( program_reference_count == 0 ) {
    > init_api()
    > program_reference_count == 1
    > } else {
    > ++program_reference_count;
    > unlock mutex
    > thread_reference_count = 1;
    > } else
    > thread_reference_count += 1;
    > }
    >
    > You only need the mutex once per thread in this design.


    Note that you hit visibility isses when you increment the variable
    outside the critical section. This is not a problem when you are only
    interested in 0 -> 1 state change because this happens inside the
    critical section which imposes a memory barrier. You'll have to
    decrement it inside a critical section only if you'd like to do
    cleanup.

    In this paticular case if you are interested in initialization only one
    could use pthread_once function.
     
    Maxim Yegorushkin, Nov 24, 2005
    #9
  10. Mark Stijnman

    Guest

    Maxim Yegorushkin wrote:
    > wrote:
    >
    > []
    >
    > > > The static count variable makes me a
    > > > little uncomfortable, especially since I expect that threads will be
    > > > used at some point. I could of course use mutexes/locks on the static
    > > > variable. Are there any other drawbacks I'm missing?

    > >
    > > The library might need per-thread cleanup, and you don't have to
    > > lockout
    > > all threads if a thread drops one reference but keeps another. So,
    > > basically
    > > i'd do (in pseudo-code)
    > >
    > > if(thread_reference_count == 0) {
    > > lock mutex
    > > if( program_reference_count == 0 ) {
    > > init_api()
    > > program_reference_count == 1
    > > } else {
    > > ++program_reference_count;
    > > unlock mutex
    > > thread_reference_count = 1;
    > > } else
    > > thread_reference_count += 1;
    > > }
    > >
    > > You only need the mutex once per thread in this design.

    >
    > Note that you hit visibility isses when you increment the variable
    > outside the critical section.


    Apparently it wasn't clear from the pseudo code that
    thread_reference_count
    is a thread-local reference count. It's outside the critical section
    because
    each thread has its own instance. Therefore, it's not visible outside
    that
    thread and doesn't need protection.

    HTH,
    Michiel Salters
     
    , Nov 24, 2005
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    267
    =?iso-8859-1?q?Stephan_Br=F6nnimann?=
    Jan 12, 2006
  2. Jess
    Replies:
    23
    Views:
    952
  3. Replies:
    5
    Views:
    2,005
    Arne Mertz
    Mar 26, 2009
  4. Taras_96
    Replies:
    3
    Views:
    601
    Michael Tsang
    Oct 30, 2009
  5. Mr.M
    Replies:
    6
    Views:
    793
Loading...

Share This Page