Global objects semantic with templates

G

Gianguz

I'd like to discuss about the opportunity to have a global objects
creator that introduces into a general framework
(suited for multithreading) a controlled semantic to manage
globals variables (objects and scalar-types).

In the following example Global is able to create objects of any kind
with and index value attached to. So a Global<0, string> is a unique
string instance object allocated into the system that can be accessed
from any point into the program simply 'creating' another instance of
Global<int, T> with the same id and type.

Like globals, destruction of these objects is delegated
until the lifetime expiration of the program.

Here is the example:

#include <string>
#include <iostream>

using namespace std;

template<int I,class T> class Global {

public:

static const int Index = I;

typedef T Type;

Global() { }

Global(const T& t) { __set(t); }

const Global& operator =(const T& t) { __set(t); }

operator T&() { return __get(); }

~Global() { }

private:

static T& __get() {
//access can be serialized here for multithreading
static T Value;

return Value;
}

static void __set(const T& t) {
//access can be serialized here for multithreading
static T& Value = __get();

Value = t;

return;
}
};


int main() {

typedef Global<0, string> Global0;
typedef Global<1, string> Global1;

Global0 a;
Global1 b;

a = "I'm A";

b = "I'm B";

cout << (string&)a << " " << (string&)b << endl;

a = b;

cout << (string&)a << " " << (string&)b << endl;

typedef Global<1, string> Global2;

Global2 c;

c = "I'm C";

cout << (string&)a << " " << (string&)b << endl;
}

Someone thinks that it can be useful? Or something like that is
already used. In that case can you give me some reference about.

Thanks,

Gianguglielmo
 
P

Paavo Helde

(e-mail address removed) (Gianguz) wrote in
I'd like to discuss about the opportunity to have a global objects
creator that introduces into a general framework
(suited for multithreading) a controlled semantic to manage
globals variables (objects and scalar-types).

In the following example Global is able to create objects of any kind
with and index value attached to. So a Global<0, string> is a unique
string instance object allocated into the system that can be accessed
from any point into the program simply 'creating' another instance of
Global<int, T> with the same id and type.

Like globals, destruction of these objects is delegated
until the lifetime expiration of the program.

Here is the example:

#include <string>
#include <iostream>

using namespace std;

template<int I,class T> class Global {

public:

static const int Index = I;

typedef T Type;

Global() { }

Global(const T& t) { __set(t); }

const Global& operator =(const T& t) { __set(t); }

operator T&() { return __get(); }

~Global() { }

private:

static T& __get() {
//access can be serialized here for multithreading
static T Value;

return Value;
}

static void __set(const T& t) {
//access can be serialized here for multithreading
static T& Value = __get();

Value = t;

return;
}
};

Just some remarks:

1. Double underscore is reserved for compiler/stdlibrary implementations.
You may not use such identifiers in your own code.

2. *Any* globals in multithreading environment are quite suspect. In your
case the possible locking as indicated by the comments is probably at the
wrong place. There is often no use for locking separately the get() and
set() functions, as the set() function may thus silently overwrite the
results of set()-s called from other threads. One solution would be to
return a proxy object from the get() function, which locks the global
until set() function call on it, and/or scope exit. But this doesn't fit
well with your nice implicit conversion operators...

3. IIRC, statics in templates have been a troublesome area for some
compilers in the past, so this approach might practically not be as
portable as one might wish.

HTH
Paavo
 
G

Gianguz

Paavo Helde said:
(e-mail address removed) (Gianguz) wrote in
news:[email protected]:
Just some remarks:

1. Double underscore is reserved for compiler/stdlibrary implementations.
You may not use such identifiers in your own code.

Right!;) Somewhat that can be used freely could be a single
underscore?
2. *Any* globals in multithreading environment are quite suspect. In your
case the possible locking as indicated by the comments is probably at the
wrong place. There is often no use for locking separately the get() and
set() functions, as the set() function may thus silently overwrite the
results of set()-s called from other threads. One solution would be to
return a proxy object from the get() function, which locks the global
until set() function call on it, and/or scope exit. But this doesn't fit
well with your nice implicit conversion operators...

I dont' clearly understand that.
If T1,T2,T3 call for instance 2 set and 1 get locking on the same
semaphore,
the get will simply take the last modified value.

For instance:

T1 T2 T3 RESULT
set('a') set('b') get() 'b'
set('b') set('a') get() 'a'
set('a') get() set('b') 'a'
set('b') get() set('a') 'b'
get() set('a') set('b') 'default'
get() set('b') set('a') 'default'

And that is the 'Faked' ;) code:

using namespace std;

class FakeSemaphore {

public:

FakeSemaphore() { }

void lock() { }

void unlock() { }

~FakeSemaphore() { }
};

static FakeSemaphore _semaphore;

template<class LOCK> class FakeGuard {

private:

FakeSemaphore* sem;

FakeGuard();

public:

FakeGuard(FakeSemaphore* s) { sem = s; sem->lock(); }

~FakeGuard() { sem->unlock(); }
};

template<int I,class T> class Global {

public:

static const int Index = I;

typedef T Type;

Global() { }

Global(const T& t) { _set(t); }

const Global& operator =(const T& t) { _set(t); return *this; }

operator T&() { return _get(); }

~Global() { }

private:

static T& _get() {
FakeGuard<FakeSemaphore> guard(&_semaphore);
static T Value;

return Value;
}

static void _set(const T& t) {
FakeGuard<FakeSemaphore> guard(&_semaphore);
static T& Value = _get();

Value = t;

return;
}
};


int main() {

typedef Global<0, string> Global0;
typedef Global<1, string> Global1;

Global0 a;
Global1 b;

a = "I'm A";

b = "I'm B";

cout << (string&)a << " " << (string&)b << endl;

a = b;

cout << (string&)a << " " << (string&)b << endl;

typedef Global<b.Index, Global1::Type> Global2;

Global2 c;

c = "I'm C";

cout << (string&)a << " " << (string&)b << endl;
}

I agree about the proxy object as a general solution but in that case
I think locking should rely on the class itself to keep it
lightweight.
Do you think that this code could produce inconsistent
concurrent r/w sequences?
3. IIRC, statics in templates have been a troublesome area for some
compilers in the past, so this approach might practically not be as
portable as one might wish.

What kind of problems? What kind of mistake can the compiler (in my
case gcc works well) produce with a simple static variable declared
into a simple 2 typename class template?

Thanks!
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top