0

I found an article i find quite interesting. There is just one thing i cannot wrap my head around. (http://molecularmusings.wordpress.com/2011/08/31/file-system-part-1-platform-specific-api-design/) The author describes a File class which is able to handle synchronous and asynchronous file operations. For the asynchronous operation he uses a self-contained object which keeps track of the asynchronous operation internally. The class looks like this:

class OsAsyncFileOperation
{
public:
  OsAsyncFileOperation(HANDLE file, size_t position);
  OsAsyncFileOperation(const OsAsyncFileOperation& other);
  OsAsyncFileOperation& operator=(const OsAsyncFileOperation& other);
  ~OsAsyncFileOperation(void);

  /// Returns whether or not the asynchronous operation has finished
  bool HasFinished(void) const;

  /// Waits until the asynchronous operation has finished. Returns the number of transferred bytes.
  size_t WaitUntilFinished(void) const;

  /// Cancels the asynchronous operation
  void Cancel(void);

private:
  HANDLE m_file;
  ReferenceCountedItem<OVERLAPPED>* m_overlapped;
};

And is used like this:

OsAsyncFileOperation ReadAsync(void* buffer, size_t length, size_t position);

Now i am wondering: What is the role of the ReferenceCountedItem<OVERLAPPED>* m_overlapped; variable? I know that this somehow counts the references, but i am not sure how it is used here, especially since the constructor is not getting passed the OVERLAPPED structure. How does this class now about the OVERLAPPED structure used in the ReadAsync or WriteAsync method? I tried to implement the ReferenceCountedItem class, since it is not specified in the article:

#pragma once

template <typename T>
class ReferenceCountedItem {

public:
    ReferenceCountedItem(T* data) :m_data(data), m_refCounter(1)
    {}

    ~ReferenceCountedItem() {}

    int addReference()
    {
        return ++this->m_refCounter;
    }

    int removeReference()
    {
        return --this->m_refCounter;
    }

private:
    T* m_data;
    int m_refCounter;
};

I am mostly unsure of how this all is sticking together. Maybe someone can explain a little bit more about it. If you need more information please let me know.

puelo
  • 5,464
  • 2
  • 34
  • 62
  • We can't see the OsAsyncFileOperation constructor, no need to make us guess at what it looks like. – Hans Passant Mar 19 '14 at 14:50
  • I think you could use `std::shared_ptr` to replace `ReferenceCountedItem` if you have it available in your compiler. – Luis Mar 19 '14 at 15:42

1 Answers1

0

Somewhere the author is allocating the OVERLAPPED struct on the heap, with new or GlobalAlloc. Then, in the copy constructor and operator=, he is copying the pointer. Since there can be multiple objects using the pointer he is using reference counting to know when it's ok to delete the OVERLAPPED pointer.

001
  • 13,291
  • 5
  • 35
  • 66
  • I am not quite sure i understand what you mean. Wouldn't the OVERLAPPED struct be allocated inside the `ReadAsync` or `WriteAsync` (because the call to ReadFile and WriteFile with the OVERLAPPED struct would happen there)? How could the `OsAsyncFileOperation` now about the pointer then? – puelo Mar 19 '14 at 15:47
  • You would have to look at the implementation of `ReadAsync()` and `WriteAsync()` to answer that. We cannot see that here. Either they are using some internal trickery to get an `OVERLAPPED` pointer into a new `OsAsyncFileOperation`, or the article does not accurately reflect what the code is really doing. – Remy Lebeau Mar 19 '14 at 16:14
  • Alright. That was what i was thinking, too. Was just not sure if i was missing something. Thank you. – puelo Mar 19 '14 at 16:16