c++ static callback method question

I have code used to monitor data received over a network.

I have a static instance of a class which is used to calculate the bitrate and has a static method as follows:

static int DataReceivedCallBack(long bytesReceived, void* userData);

Open in new window


This function is called from inside various dlls whenever data is received.

int MyBandwidthManager::DataReceivedCallBack(long dataLength, void* userData  )
{
     MyBandwidthManager* bwMgr = static_cast<MyBandwidthManager*>(userData);
     bwMgr->UpdateBitrate(dataLength);
     
     return 0;
}

void MyBandwidthManager::UpdateBitrate( long bytesReceived)
{		
		unsigned long timeStampNow =  timeGetTime();
                // blah blah
                // do bitrate calculations
 }

Open in new window


The various dlls in question are used to receive video from different sources, I pass the DataReceivedCallBack into these dlls as a callback function.

The problem I am having is that I see sometimes (using debug messages) that timeStampNow contains the exact same time but the function DataReceivedCallBack has been called by two different dlls.

I thought that the fact that the method was static meant that it could be called only once at any one time??? And not twice at the same time??

To calculate the bite rate correctly I need the timestamp between incoming data to be always incrementing.

Any ideas/help??

Thanks
Wanting2LearnManAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

evilrixSenior Software Engineer (Avast)Commented:
The fact the function is static has no baring on this. C++ has no concept of threads. A function can be entered by any number of threads at any time unless you use a mutex primitive to prevent this.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
HooKooDooKuCommented:
A static member function is simply a class function that can be called without a class reference.

Typically, when a class member function is called, a hidden 'this' pointer is passed to the class.  That way, when the function attempts to access a member variable, under the hood, the compiler accesses the variable with the hidden 'this' pointer.

But with a static member function, no 'this' pointer is provided.  As such, the static member function is limited to accessing static member variables.

Now the only reason a static member function can access the static member variables is because when a member variable is declared, all instances of the class share the same variable.  Since a static member variable is known to all instances of the class, then even the static member function that has no 'this' pointer can still access the static variables.

As evilrix pointed out, if you want multiple threads or processes to call the same function, yet insure uniqueness of the time stamp, then you would have to utilize a thread synchronization object.  If all the threads accessing your function are in multiple processes (programs), then you could use a CMutex object to only allow one thread to get a timestamp at a time.  If all the threads are in a multithreaded process, then you can use the more efficient CCriticalSection object.

Of course you still have to do more than limit access to the function call to just one thread/process at a time.  timeGetTime returns the time in milliseconds.  With modern GHz speed processes with multiple cores running, thousands of instruction can be executed in one millisecond.  So you would need to modify your function to first only allow one thread/process to execute the code at once, you would also have to add logic that tracks the most recent time value that was returned and make sure the current time being returned is greater than the previous one.

0
HooKooDooKuCommented:
Opps, change the text

"Now the only reason a static member function can access the static member variables is because when a member variable is declared, all instances of the class share the same variable."

to

"Now the only reason a static member function can access the static member variables is because when a member variable is declared STATIC, all instances of the class share the same variable."
0
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

Wanting2LearnManAuthor Commented:
Thanks guys, good interesting points.

I have added a lock, and I noticed that sometimes the same time was still being returned (due to the speed of the processor and timeGetTime returning milisecs) - so I added a Sleep(1) in for now which should be good enough for my calculations.
 
0
jkrCommented:
Also, you are using 'timeGetTime()', which is only 'accurate' up to 1ms (and that's optimistic, you could as well use 'GetTickCount()'), so chances are that the time stamps returned by that API seem identical regarding their values, but in fact are not, because both events occured within the same resolution window.
0
sarabandeCommented:
if you want the function to run exclusively you could add

static CRITICAL_SECTION cs;
static bool once = true;
if (bwMgr == NULL && once == false)
{
    DeleteCriticalSection(&cs);
    return;
}
if (once)
{
   once = false;
   InitializeCriticalSection(&cs);
}
EnterCriticalSection(&cs);
bwMgr->UpdateBitrate(dataLength);
Sleep(1000);
LeaveCriticalSection(&cs);

Open in new window


around the UpdateBitrate call. it would make the UpdateBitRate an exclusively running code, what means that a second thread must wait for the first thread. the Sleep would guarantee that a next timestamp has a different value.

the code above is not quite safe cause the very first call should be not same time with a second call cause the initializing part is not thread-safe.

another approach would be to always add (like adding milliseconds) an incremented number to the timestamp. you can get  the number from a static int initialized to 0. to make that fully thread-safe do the incrementation by a call to InterlockedIncrement though that probably is overkill and a normal ++ increment would do also.

Sara

Sara
0
sarabandeCommented:
seems i was a little bit slow with my suggestions ...

Sara
0
sarabandeCommented:
if milliseconds did not prevent from getting the same timestamp you probably better should use the InterlockedIncrement in order to make the incrementing thread-safe.

static LONG volatile uni = 0;
LONG toadd = InterlockedIncrement(&uni);

Open in new window


the 'toadd' would be unique even if the threads would run same time.

Sara
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.