|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#21 | |
|
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
è possibile implementare parte dei metodi nell'exe e usarli nella DLL?? e allora ho risolto... ![]() cmq no, gli handle scambiati tra DLL ed exe non fanno casino: sono validi in tutto il processo. |
|
|
|
|
|
|
#22 | ||||||
|
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
Quote:
scherzi a parte, ti ringrazio vivamente per la tua disponibilità! Quote:
class CResource ... class CAccount : public CResource ... class CAccountImpl : public CAccount ... dove CAccountImpl è l'implementazione della DLL di CAccount; CAccountImpl è quella che di fatto viene istanziata, anche se è sconosciuta all'exe. Quote:
Quote:
Quote:
|
||||||
|
|
|
|
|
#23 | |
|
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
ciascun oggetto (non pensiamo ora alle classi, pensiamo agli oggetti già istanziati) deve avere due mutex e un paio di altri campi per gestire l'esclusione; tutti i thread hanno lo stesso puntatore di un determinato oggetto, e vedono gli stessi suoi campi; a seconda che chiamino LockRead, LockWrite, ecc., bloccano e sbloccano il mutex 1 o il 2 o entrambi, ma comunque per ogni oggetto i due mutex su cui lavorano sono gli stessi. |
|
|
|
|
|
|
#24 |
|
Senior Member
Iscritto dal: May 2000
Messaggi: 1459
|
class CResource {
public: void CreateMutexes(); ... //i tuoi metodi astratti private: HANDLE m_hMutex1,m_hMutex2; }; ora: siccome sarà l'eseguibile a dover lanciare createMutexes(), ti fai un bel resource.cpp in cui implementi CreateMutexes() nel progetto dell'eseguibile. Siccome mi pare di aver capito ke la DLL dovrà solo istanziare oggetti di classi derivate da CResource, nn hai bisogno di includere il .cpp dove definisci CreateMutexes() nella DLL, in quanto il codice nn è necessario (la funzione nn verrà mai eseguita, quindi dovrebbe linkare la DLL tranquillamente, al limite includi pure resource.cpp nella DLL). Così dovrebbe funzionare ciauz |
|
|
|
|
|
#25 | |
|
Senior Member
Iscritto dal: Oct 2002
Città: San Jose, California
Messaggi: 11794
|
Quote:
E guarda i seguenti due design pattern se ti possono aiutare: - Factory Method - Builder Vedi se questa idea ha senso, lato client: Codice:
// anche qui magari ti puo' servire un factory in futuro, per ora non mi sembra
CLock* aLock = new CLockImpl();
// qui il factory method serve
// uso una stringa, ma ovviamente puoi usare quello che ti pare per richiedere
// la creazione di un qualche tipo di risorsa in particolare
CResouce* aResource = CResource::Create("MyResourceType", aLock);
...
CResource::Destroy(aResource);
Una possibilita' e' di avere un metodo statico di distruzione, invece di chiamare direttamente il distruttore, perche' e' buona norma creare/distruggere la memoria nello stesso modulo. Immagina che succede se la DLL usa un heap differente, tu pensi che la delete distrugga l'oggetto invece va a sovrascrivere memoria a caso (e mi e' successo). Dichiare esplicitamente un distruttore privato nell'interfaccia e non implementarlo, cosi' costringi il cliente ad usare solo il tuo metodo Destroy. Se pensi che tanto nessuno sara' cosi' fesso da usare l'operatore delete quando c'e' un metodo Destroy, sappi che lo fanno (e mi e' successo pure questo). Se sei il solo a programmare, ti dimenticherai un giorno che esiste il metodo Destroy e userai la delete In C# e Java tutti questi problemi non esistono
__________________
"We in the game industry are lucky enough to be able to create our visions" @ NVIDIA Ultima modifica di fek : 30-07-2005 alle 13:33. |
|
|
|
|
|
|
#26 | |
|
Senior Member
Iscritto dal: Oct 2002
Città: San Jose, California
Messaggi: 11794
|
Quote:
L'interfaccia fra una DLL e il resto del mondo dovrebbe sempre essere esposta via interfacce pure. COM e' nato proprio con lo scopo di formalizzare questa convenzione.
__________________
"We in the game industry are lucky enough to be able to create our visions" @ NVIDIA |
|
|
|
|
|
|
#27 | |
|
Senior Member
Iscritto dal: Oct 2002
Città: San Jose, California
Messaggi: 11794
|
Quote:
Puoi sempre mantenere l'interfaccia di CLock anche in CResource ed implementare un CResourceBase che contiene un'istanza di CLock passata dall'esterno e implementa l'interfaccia CResource limitandosi a delegare i Lock/Release all'oggetto CLock, per semplificare l'uso da parte del cliente. Alla fine hai due classi ognuna con una sola responsabilita: - CLock: si occupa della sincronizzazione - CResource: gestisce la risorsa e delega i compiti di sincronizzazione
__________________
"We in the game industry are lucky enough to be able to create our visions" @ NVIDIA |
|
|
|
|
|
|
#28 | |
|
Senior Member
Iscritto dal: May 2000
Messaggi: 1459
|
Quote:
nn era specificato dovesse essere un'interfaccia pura Per curiosità, quali problemi possono scaturire? In genere, è una tecnica che funziona abbastanza bene (l'ho usata spesso) ciauz |
|
|
|
|
|
|
#29 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Perchè non ti fai un oggetto (anzi due mi sembra di capire) un CMutex (attento che in MFC esiste già) ?
Lo metti come membro della CResource e lo inzializzi nel costruttore della CResource... Le classi derivate avranno già tali membri inizializzati... |
|
|
|
|
|
#30 | |
|
Senior Member
Iscritto dal: Oct 2002
Città: San Jose, California
Messaggi: 11794
|
Quote:
Oppure una qualunque variazione sul tema. Una volta che ci si abitua a lavorare per interfacce e' tutto molto piu' semplice. Io uso quasi sempre interfacce pure come confine fra "aree" diverse anche nello stesso modulo per mantenere le interfacce stesse pulite.
__________________
"We in the game industry are lucky enough to be able to create our visions" @ NVIDIA |
|
|
|
|
|
|
#31 |
|
Senior Member
Iscritto dal: May 2000
Messaggi: 1459
|
interessante, nn ci avevo mai pensato
[OT] e nelle situazioni in cui verrebbe naturale spostare funzionalità comuni nella classe base astratta, come ti comporti? Composition? Ad esempio, una classe con un template method in questo modo nn sarebbe utilizzabile...o c'è qualke trukketto? [/OT] ciauz |
|
|
|
|
|
#32 | |
|
Senior Member
Iscritto dal: Oct 2002
Città: San Jose, California
Messaggi: 11794
|
Quote:
Altrimenti faccio cose cosi': Codice:
Animation <- AnimationBase <- AnimationProxy (AnimationImpl)
<- AnimationImpl
() compisizione Chi riconosce il design pattern? (facile facile)
__________________
"We in the game industry are lucky enough to be able to create our visions" @ NVIDIA |
|
|
|
|
|
|
#33 |
|
Senior Member
Iscritto dal: May 2000
Messaggi: 1459
|
è (dovrebbe essere
ciauz |
|
|
|
|
|
#34 |
|
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
dunque dunque: grazie ai vostri spunti il design per il quale ho optato è il seguente: la thread-safety (i due mutex, l'intero e il flag) è gestita a parte in CLockImpl, la cui interfaccia astratta è CLock e sta nell'header condiviso. (btw: non uso MFC perché il sorgente deve essere il più possibile portabile; per ora c'è solo un file che deve essere rifatto per Linux, mettendoci anche CLockImpl saranno due).
CResource non deriva da CLock, ma tutte le classi interne della DLL derivate da CResource o da interfacce derivate da CResource (come CAccount) vengono istanziate dalla DLL sotto richiesta dell'eseguibile tramite opportuni metodi esportati dalla DLL stessa; tutti questi metodi tra i parametri vogliono anche un puntatore a un'istanza di CLock creata dall'exe. per costringere la DLL ad implementare CResource utilizzando un'istanza di CLock, metterò in CResource un costruttore puro virtuale (si può fare, vero? ) con un parametro CLock*.ora però vengono i problemoni: la distruzione di tutto sto macello! come consiglia giustamente fek, conviene sempre deallocare memoria nello stesso modulo in cui la si alloca (altrimenti se i moduli usano heap differenti possiamo allegramente assistere a curiosi fenomeni cosmici); bene: qui è praticamente il contrario... le cose allocate da uno vengono deallocate dall'altro... allora, le implementazioni di CResource o delle interfacce derivate vengono allocate dalla DLL e vengono distrutte dall'exe; inoltre ciascuna di esse contiene un'istanza di CLock creata dall'exe e deallocata dalla DLL... ![]() per distruggere CResource posso (come suggerisce fek) metterci un metodo astratto Destroy implementato dalla DLL che deve chiama il distruttore (che metterò come membro privato per evitare che un giorno io mi dimetichi dell'esistenza di Destroy); in tal modo a distruggere le istanze di CResource è la DLL (non più l'exe), la quale quindi deve anche occuparsi di distruggere il CLock, e questo non va bene perché sennò assistiamo ai fenomeni cosmici; e io come faccio? semplice!! uso la tecnica del Destroy anche in CLock!!! risolto! (ho capito la soluzione mentre scrivevo grazie a tutti, specie fek EDIT: vorrei un ultimo vostro parere: ma è proprio necessario un design così complesso? non si può proprio fare qualcosa di più semplice?
Ultima modifica di 71104 : 31-07-2005 alle 18:41. |
|
|
|
|
|
#35 | |
|
Senior Member
Iscritto dal: Oct 2002
Città: San Jose, California
Messaggi: 11794
|
Quote:
Secondo me e' troppo complesso, sono certo che puoi migliorare le specifiche e semplificare il design. E non usare quelle C di fronte al nome della classe!
__________________
"We in the game industry are lucky enough to be able to create our visions" @ NVIDIA |
|
|
|
|
|
|
#36 | ||
|
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
e a questo punto inizio ad essere seriamente in difficoltà: non riesco a creare un oggetto implementato parzialmente da un modulo e parzialmente da un altro... ![]() eppure imho questo è quello che va fatto: il concetto di "risorsa" nel mio progetto deve essere implementato completamente dalle varie DLL, tranne l'esclusione che preferisco implementare nell'exe (in maniera tale da avere un'implementazione unica). certo, implementando l'esclusione in ciascuna delle DLL si risolve tutto quanto, ma è "brutto" da fare, sei d'accordo anche tu? ![]() Quote:
e poi le ho usate dappertutto ormai ![]() il massimo che posso concederti è di usare le "I" al posto nelle "C" nelle classi astratte... |
||
|
|
|
|
|
#37 |
|
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
alla fine ho risolto così (stavolta penso proprio che sia la soluzione definitiva):
Codice:
class CLock {
public:
virtual void LockRead() = 0;
virtual void UnlockRead() = 0;
virtual void LockWrite() = 0;
virtual void UnlockWrite() = 0;
virtual void Destroy() = 0;
};
class CResource : public CLock {
public:
virtual CLock *GetLock() = 0;
virtual unsigned int GetID() = 0;
virtual COUNTER GetCounter(unsigned int uCode) = 0;
virtual void SetCounter(unsigned int uCode, COUNTER value) = 0;
virtual void Destroy() = 0;
};
il design una debolezza ce l'ha, ma alla fine ho detto kissene la debolezza sarebbe che la DLL è costretta ad assegnare l'oggetto CLock che le viene passato alla risorsa che deve creare; alla fine non è neanche tanto una debolezza dal momento che quando l'exe chiama GetLock la DLL dovrà pur restituire qualcosa se restituisce NULL sono costretto a scaricare la DLL e mostrare sulla console un messaggio di errore che dice in poche parole che quella DLL non funziona. ultima cosa: qualcuno mi dice se la mia versione dell'esclusione va bene? Codice:
CLockImpl::CLockImpl() {
VERIFY(hMutex1 = CreateMutex(NULL, FALSE, NULL));
VERIFY(hMutex2 = CreateMutex(NULL, FALSE, NULL));
uReaders = 0;
fWriting = 0;
}
CLockImpl::~CLockImpl() {
VERIFY(CloseHandle(hMutex1));
VERIFY(CloseHandle(hMutex2));
}
void CLockImpl::LockRead() {
VERIFY(WAIT_OBJECT_0 == WaitForSingleObject(hMutex1, INFINITE));
VERIFY(WAIT_OBJECT_0 == WaitForSingleObject(hMutex2, INFINITE));
uReaders++;
while (fWriting);
VERIFY(ReleaseMutex(hMutex2));
VERIFY(ReleaseMutex(hMutex1));
}
void CLockImpl::UnlockRead() {
VERIFY(WAIT_OBJECT_0 == WaitForSingleObject(hMutex1, INFINITE));
ASSERT(uReaders);
uReaders--;
VERIFY(ReleaseMutex(hMutex1));
}
void CLockImpl::LockWrite() {
VERIFY(WAIT_OBJECT_0 == WaitForSingleObject(hMutex2, INFINITE));
while (fWriting);
fWriting = 1;
while (uReaders);
VERIFY(ReleaseMutex(hMutex2));
}
void CLockImpl::UnlockWrite() {
fWriting = 0;
}
void CLockImpl::Destroy() {
delete this;
}
Ultima modifica di 71104 : 01-08-2005 alle 13:37. |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 03:03.












) con un parametro CLock*.









