views:

304

answers:

6

I have an object for which I'd like to track the number of threads that reference it. In general, when any method on the object is called I can check a thread local boolean value to determine whether the count has been updated for the current thread. But this doesn't help me if the user say, uses boost::bind to bind my object to a boost::function and uses that to start a boost::thread. The new thread will have a reference to my object, and may hold on to it for an indefinite period of time before calling any of its methods, thus leading to a stale count. I could write my own wrapper around boost::thread to handle this, but that doesn't help if the user boost::bind's an object that contains my object (I can't specialize based on the presence of a member type -- at least I don't know of any way to do that) and uses that to start a boost::thread.

Is there any way to do this? The only means I can think of requires too much work from users -- I provide a wrapper around boost::thread that calls a special hook method on the object being passed in provided it exists, and users add the special hook method to any class that contains my object.

Edit: For the sake of this question we can assume I control the means to make new threads. So I can wrap boost::thread for example and expect that users will use my wrapped version, and not have to worry about users simultaneously using pthreads, etc.

Edit2: One can also assume that I have some means of thread local storage available, through __thread or boost::thread_specific_ptr. It's not in the current standard, but hopefully will be soon.

A: 

Short of a pimpl style implementation that does a threadid check before every dereference I don't see how you could do this:

 class MyClass;
 class MyClassImpl {
     friend class MyClass;
     threadid_t owning_thread;
 public:
     void doSomethingThreadSafe();
     void doSomethingNoSafetyCheck();
 };

 class MyClass {
     MyClassImpl* impl;
 public:
     void doSomethine() {
         if (__threadid() != impl->owning_thread) {
             impl->doSomethingThreadSafe();
         } else {
             impl->doSomethingNoSafetyCheck();
         }
     }
 };

Note: I know the OP wants to list threads with active pointers, I don't think that's feasible. The above implementation at least lets the object know when there might be contention. When to change the owning_thread depends heavily on what doSomething does.

jmucchiello
+3  A: 

In general, this is hard. The question of "who has a reference to me?" is not generally solvable in C++. It may be worth looking at the bigger picture of the specific problem(s) you are trying to solve, and seeing if there is a better way.

There are a few things I can come up with that can get you partway there, but none of them are quite what you want.

You can establish the concept of "the owning thread" for an object, and REJECT operations from any other thread, a la Qt GUI elements. (Note that trying to do things thread-safely from threads other than the owner won't actually give you thread-safety, since if the owner isn't checked it can collide with other threads.) This at least gives your users fail-fast behavior.

You can encourage reference counting by having the user-visible objects being lightweight references to the implementation object itself [and by documenting this!]. But determined users can work around this.

And you can combine these two-- i.e. you can have the notion of thread ownership for each reference, and then have the object become aware of who owns the references. This could be very powerful, but not really idiot-proof.

You can start restricting what users can and cannot do with the object, but I don't think covering more than the obvious sources of unintentional error is worthwhile. Should you be declaring operator& private, so people can't take pointers to your objects? Should you be preventing people from dynamically allocating your object? It depends on your users to some degree, but keep in mind you can't prevent references to objects, so eventually playing whack-a-mole will drive you insane.

So, back to my original suggestion: re-analyze the big picture if possible.

+1  A: 

Usually you cannot do this programmatically.

Unfortuately, the way to go is to design your program in such a way that you can prove (i.e. convince yourself) that certain objects are shared, and others are thread private.

The current C++ standard does not even have the notion of a thread, so there is no standard portable notion of thread local storage, in particular.

Tobias
I'm willing to use __thread and boost::thread_specific_ptr for my purposes. I'll edit my original post to reflect this. I think you're still correct in general though.
Joseph Garvin
If you find out a smart way, let me know. I am sorry that I cannot give you more specific help here.
Tobias
A: 

If I understood your problem correctly I believe this could be done in Windows using Win32 function GetCurrentThreadId(). Below is a quick and dirty example of how it could be used. Thread synchronisation should rather be done with a lock object.

If you create an object of CMyThreadTracker at the top of every member function of your object to be tracked for threads, the _handle_vector should contain the thread ids that use your object.

#include <process.h>
#include <windows.h>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;


class CMyThreadTracker
{

    vector<DWORD> & _handle_vector;
    DWORD _h;
    CRITICAL_SECTION &_CriticalSection;
public:
    CMyThreadTracker(vector<DWORD> & handle_vector,CRITICAL_SECTION &crit):_handle_vector(handle_vector),_CriticalSection(crit)
    {
     EnterCriticalSection(&_CriticalSection); 
     _h = GetCurrentThreadId();
     _handle_vector.push_back(_h);
     printf("thread id %08x\n",_h);
     LeaveCriticalSection(&_CriticalSection);
    }

    ~CMyThreadTracker()
    {
     EnterCriticalSection(&_CriticalSection); 
     vector<DWORD>::iterator ee = remove_if(_handle_vector.begin(),_handle_vector.end(),bind2nd(equal_to<DWORD>(), _h));
     _handle_vector.erase(ee,_handle_vector.end());
     LeaveCriticalSection(&_CriticalSection);
    }
};

class CMyObject
{
    vector<DWORD> _handle_vector;

public:
    void method1(CRITICAL_SECTION & CriticalSection)
    {
     CMyThreadTracker tt(_handle_vector,CriticalSection);

     printf("method 1\n");

     EnterCriticalSection(&CriticalSection);
     for(int i=0;i<_handle_vector.size();++i)
     {
      printf(" this object is currently used by thread %08x\n",_handle_vector[i]);
     }
     LeaveCriticalSection(&CriticalSection);

    }
};

CMyObject mo;
CRITICAL_SECTION CriticalSection;

unsigned __stdcall ThreadFunc( void* arg )
{

    unsigned int sleep_time = *(unsigned int*)arg;
    while ( true)
    {
        Sleep(sleep_time);
     mo.method1(CriticalSection);
    }

    _endthreadex( 0 );
    return 0;
} 

int _tmain(int argc, _TCHAR* argv[])
{

    HANDLE hThread;
    unsigned int threadID;

    if (!InitializeCriticalSectionAndSpinCount(&CriticalSection, 0x80000400) ) 
        return -1;

    for(int i=0;i<5;++i)
    {
     unsigned int sleep_time = 1000 *(i+1);

     hThread = (HANDLE)_beginthreadex( NULL, 0, &ThreadFunc, &sleep_time, 0, &threadID );
     printf("creating thread %08x\n",threadID);
    }

    WaitForSingleObject( hThread, INFINITE );

    return 0;
}

EDIT1: As mentioned in the comment, reference dispensing could be implemented as below. A vector could hold the unique thread ids referring to your object. You may also need to implement a custom assignment operator to deal with the object references being copied by a different thread.

class MyClass
{
public:
static MyClass & Create()
    {
 static MyClass * p = new MyClass();

 return *p;
    }
    static void Destroy(MyClass * p)
    {
     delete p;
    }

private:
    MyClass(){}
    ~MyClass(){};
};

class MyCreatorClass
{
    MyClass & _my_obj;
public:
MyCreatorClass():_my_obj(MyClass::Create())
    {

    }

    MyClass & GetObject()
    {
     //TODO: 
     // use GetCurrentThreadId to get thread id
     // check if the id is already in the vector
     // add this to a vector

     return _my_obj;
    }

    ~MyCreatorClass()
    {
     MyClass::Destroy(&_my_obj);
    }

}; 

int _tmain(int argc, _TCHAR* argv[])
{
    MyCreatorClass mcc;

    MyClass &o1 = mcc.GetObject();

    MyClass &o2 = mcc.GetObject();

    return 0;
}
Indeera
The problem with this kind of solution is that the new thread may hold on to the reference to the object without calling any of its methods until an arbitrary amount of time has passed. If I want to take any sort of action when the ref count reaches a certain value, that's a problem, since the value might be wrong for awhile. I could write a custom start_new_thread function that would make sure some method on the object was called, but that doesn't solve the issue of objects containing my object.
Joseph Garvin
I'm guessing in that case you could implement a factory pattern dispensing references to your object. And record the thread ids in the factory function.
Indeera
@JG wow, that's understandable but becomes even trickier when you need to count even UNUSED references. Indeera's idea of a factory may work better. A reference-counting like pointer strategy might be possible, though, just as a germ of an idea.
SPWorley
A: 

The solution I'm familiar with is to state "if you don't use the correct API to interact with this object, then all bets are off."

You may be able to turn your requirements around and make it possible for any threads that reference the object subscribe to signals from the object. This won't help with race conditions, but allows threads to know when the object has unloaded itself (for instance).

Max Lybbert
A: 

To solve the problem "I have an object and want to know how many threads access it" and you also can enumerate your threads, you can solve this problem with thread local storage. Allocate a TLS index for your object. Make a private method called "registerThread" which simply sets the thread TLS to point to your object.

The key extension to the poster's original idea is that during every method call, call this registerThread(). Then you don't need to detect when or who created the thread, it's just set (often redundantly) during every actual access.

To see which threads have accessed the object, just examine their TLS values.

Upside: simple and pretty efficient.

Downside: solves the posted question but doesn't extend smoothly to multiple objects or dynamic threads that aren't enumerable.

SPWorley
This doesn't work unfortunately, see my comment on Indeera's answer.
Joseph Garvin