globalny obiekt w DLL

0

Cześć,

Piszę właśnie sterownik do telefonii (protokół SIP) w architekturze MS TAPI – ale to chyba nie ma większego znaczenia. Jest to po prostu DLL stworzona przy pomocy pewnego kreatora. Zawiera klasy i ich metody, które obsługują żądania „ z zewnątrz” – wybaczcie jeśli opis jest mało precyzyjny ;)
Problemem jest dołączenie kodu odpowiedzialnego za obsługę komunikacji SIP- mam taki fragment, który sam działa. Jak poda sie adres to wysyła wiadomości do inicjalizacji połączenia a w innym wypadku „czeka-nasłuchuje” na przyjście połączenia z zewnątrz. Gdy zamieściłem go w jednej z metod to zadziałał prawidłowo, ale jednocześnie chcę mieć możliwość wywoływania innych metod a w takim wypadku musze zakończyć działanie tego fragmentu (zlikwidować obiekty tworzone do obsługi SIP) i ewentualnie tworzyć nowe, które mają się nijak to poprzedniego i przez to mam jakby zupełnie nowe połączenie - czego nie chcę. Ubrałem to wszystko w klasę i stworzyłem metody ale efekt jest w zasadzie taki sam jeśli tworze obiekt tej klasy w tych metodach.

To co by mnie urządzało to stworzenie takiego jednego globalnego obiektu, do którego można by się odwoływać z innych metod i żeby on sobie mógł działać niezależnie. Nie jestem ekspertem w C++ i będę wdzięczny za wszelkie rady.

pozdrawiam
Michał

0

Gdy zamieściłem go w jednej z metod to zadziałał prawidłowo, ale jednocześnie chcę mieć możliwość wywoływania innych metod a w takim wypadku musze zakończyć działanie tego fragmentu (zlikwidować obiekty tworzone do obsługi SIP) i ewentualnie tworzyć nowe

mozesz to troche rozwinac? to nie wyglada naturalnie.. jezeli tak jest jak zrozumialem, to wszystkie metody korzystaja z jakichs wspoldzielonych zmiennych i raczej czeka Cie rozplatywanie niz opakowywanie makaronu w duza klasobiektosingleton

0

historia jest taka:
mam program do obsługi SIPa, który działa jako samodzielny exec - można dzwonić lub odbierać połączenie.
Wziąłem ten program i z małymi poprawkami jedną część wsadziłem do jednego z plików nagłówkowych mojego projektu a drugą część do wnętrza metody, tak że gdy system wywołuję określoną funkcję, uruchamiana jest moja metoda z tym kodem. Problem jest taki, że ten wstawiony fragment jest dostępny tylko w tej metodzie przez co np. nie mogę go zakończyć gdy system wywoła inną funkcję w moim DLL, w której zawarty by był kod do likwidacji stworzonych obiektów przez wspomniany wcześniej fragment kodu.Co gorsza jeśli ten kod "czeka" na połączenie, to blokuje całą DLL bo nie może wyjść z tej metody.
Myślę,że rozwiązaniem było by coś takiego ,że w metodzie w której chciałbym zainicjować połączenie ( wygląda ona tak
bool CSIPTSPLine::OnMakeCall(RTMakeCall* pRequest, LPCVOID lpBuff)
było by tylko inicjowanie jakiegoś globalnego obiektu, który zawierał by kod z tego programu SIP i działał nie wewnątrz tej metody a tak "z boku", dzięki czemu z metody do usuwania połączenia można by było wywołać odpowiednią metodę. Ten globalny obiekt był by klasy, którą zgaduję, można by stworzyć i która właśnie by udostępniała metody to inicjalizacji, i usuwania tego obiektu.

nie wiem czy jeszcze bardziej nie zamieszałem ;)

0

nie, akurat dosc rozjasniles. wydaje mi sie ze nie slyszales o jednym dosc istotnym pojeciu:)

Twoj problem z oczekiwaniem w glownej mierze nie polega na nie-obiektowosci tylko tego, ze ktos najprawdopodobniej napisal ten programik na pale, robiac wszystko krok po kroku, 'synchronicznie', w jednym (glownym) watku..

wlasciwie, jak na razie widze tylko dwa mozliwe rozwiazania, przy czym najkrotsze to .. owo brakujace pojecie, "threads, wątki"

zamiast wywolywac metode ktora trwa za dlugo ot tak sobie, tworzysz nowy watek i kazesz mu ja wykonac. to wlanie bedzie doslownie "wykonanie jej tak z boku". dodatkowy plus jest taki, ze watek mozesz zawsze ubic jak Cie zdenerwuje. minus - musisz uwaznie synchronizowac watek boczny z glownym, zwlasza przy wymianie danych pomiedzy nimi. inaczej mozesz przypadkiem odczytac/zapisac nie calkiem to co bys sadzil..

0

No tak jest z tym programem - leci sobie ciurkiem. Niestety nie mam teraz czasu na wgłębienie się w tą bibliotekę, żeby samemu spróbować to dołączyć do mojego sterownika.

tworzysz nowy watek i karzesz mu ja wykonać.

o to pewnie by chodziło,ale z tymi wątkami nie miałem nogdy do czynienia kwestia taka czy z moimi zdolnościami i czasem dało by to radę zrobić w rozsądnym czasie.

Poczytałem trochę o singeltonach i spróbuję to zastosować u siebie. znalazłem taki przykład:

class TextureManager	//nasza glowna klasa zarzadcy tekstur
{
	static TextureManager* singleton;	//wskaznik na jedyny obiekt klasy TextureManager

public:
	TextureManager()	//domyslny konstruktor
	{
		assert(singleton == 0);	//jezeli obiekt juz istnieje, a sprobowano stworzyc go ponownie,
				//to znaczy, ze cos jest nie tak
		singleton = this;	//ten obiekt staje sie singletonem

		//... Tu zawarł bym swój kod do obsługi SIP
	}
	
	TextureManager()	//domyslny destruktor
	{
		assert(singleton != 0);	//jezeli obiekt juz nie istnieje, a probujemy go zniszczyc,
				//to znaczy, ze cos jest nie tak
		singleton = 0;	//jedyny obiekt przestal istniec
	}

	//... inny kod

	static TextureManager& GetTextureManager()	//funkcja zwracajaca jedyny obiekt
	{
		return singleton;
	}
};

//jeszcze definicja zmiennej statycznej
TextureManager* TextureManager::singleton = 0;

w weekend spróbuję ogarnąc ten temat.

quetzalcoatl, dzięki za odpowiedzi i jeśli jest tu na forum jakiś sposób na wyrażenie tego inaczej (jakieś punkty czy coś, bo nie zauważyłem ;) ) to chętnie zadziałam.

0
s-michael napisał(a)

assert(singleton == 0); //jezeli obiekt juz istnieje, a sprobowano stworzyc go ponownie, to znaczy, ze cos jest nie tak

asser w release = fail;

0

No fakt, przydałoby się raczej jakieś:
if( 0!=singleton ) throw runtime_exception("hej! co robisz?!");
W ogóle to singletona w C++ można zrobić trochę bardziej elegancko:

#include <iostream>
#include <windows.h>
using namespace std;

class ScreenObject {
    private:
        /* jakieś składowe */
        int r,w;

        /* blokujemy tworzenie i kopiowanie, konstruktory prywante
           więc nikt ich nie wywoła */
        ScreenObject() { r=w=0; cout << "hello" << endl; }
        ScreenObject(const ScreenObject&);

    public:
        /* niszczenie niech będzie dostępne, a co tam */
        ~ScreenObject() { cout << "bye" << endl; }

        /* tworzyć nie można konstruktorem, to trzeba tą funkcją */
        static ScreenObject& create() {
            /* metoda klasy może wołać prywatne rzeczy, m.in konstruktory
               w metodzie tworzony jest 1 obiekt, istniejący od momentu
               pierwszego wywołania funkcji do zakończenia programu
            */
            static ScreenObject instance;
            /* nie zwracamy użytkownikowi obiektu, tylko referencję */
            return instance;
            }

        void write() { cout << "writing: " << ++w << endl; }
        void read() { cout << "reading: " << ++r << endl; }
    };

/* a dobra, kosmetyka, żeby ludzie nie musieli się bawić z &
   nasz Screen jest referencją, a nie obiektem, ale na "zewnątrz"
   nie trzeba tego ciągle podkreślać
*/
typedef ScreenObject& Screen;

/* A no właśnie, funkcja w stylu Javowym. Przekazujemy argument przez wartość.
   Ale argumentem nie jest obiekt, lecz referencja. */
void do_something(Screen s) {
    s.read();
    s.write();
    }

int main() {
    /* praktycznie całą robotę: sprawdzenie czy obiekt jest jeden
       odwala za nas kompilator */

    Screen first = ScreenObject::create();
    // Screen second; /* musi być nadana wartość, nie pójdzie */
    // ScreenObject third; /* konstruktor prywatny, nie pójdzie */

    /* nie tworzymy drugiego ekranu tak naprawdę,
       a referencję do już istniejącego */
    Screen this_is_not_copy = first;

    do_something(first);
    do_something(this_is_not_copy);

    return 0;
    }

Ale to tak na boku, bo singleton to sposób na to, żeby mieć jeden obiekt i tylko jeden. Czyli kontrolujesz ilość kopii danych. Do uruchamiania kodu w tle to ci raczej nie posłuży. Bez wątków raczej się nie obejdzie, ale Ty nie panikuj, bo to naprawdę nie jest jakaś czarna magia (przynajmniej jeśli chodzi o podstawową teorię - praktyka i synchronizacja potrafi dobijać).
Pod Windowsa to piszesz? No miejmy nadzieję, że tak, i że się przyda taki przykład:

#include <iostream>
#include <iomanip>
#include <windows.h>

using namespace std;

bool please_stop = false;

/* To będzie hulało w tle */
DWORD WINAPI some_code(void*) {
    cout << "Thread start" << endl;
    for(int i=0; i<10; i++) {
        Sleep(150);
        cout << "A" << i << " " << flush;
        /* jakbyśmy chcieli wątek wcześniej zabić */
        if(please_stop) break;
        }

    cout << endl << "Thread end" << endl;
    return 0;
    }

int main() {

    // uruchamiamy kod w tle
    DWORD background_id;
    HANDLE background = CreateThread(0, 0, some_code, 0, 0, &background_id);

    // robimy coś w głównym wątku
    for(int i=0; i<10; i++) {
        Sleep(100);
        cout << "X" << i << " " << flush;
        }

    // dajemy sygnał, żeby tło się zamknęło
    please_stop = true;
    cout << endl << "Closing..." << endl;

    // czekamy maksymalnie sekundę na tło, żeby się zamkło
    DWORD result = WaitForSingleObject(background, 1000);

    // jak się zamkło, to super
    if( WAIT_OBJECT_0 == result ) {
        // zwalniamy klamoty
        CloseHandle(background);
        cout << endl << "Application end." << endl;
        }
    else {
        // coś poszło nie tak. nie chce nam się dochodzić co.
        cout << endl << "Unknown error. Application terminated." << endl;
        }
    return 0;
    }

Dopisane:
A ja głupi jestem. Zobaczyłem w google co to MS TAPI. I ja się zastanawiałem, czy Windows... ;)

0

dopiero teraz miałem trochę czasu żeby do tego usiąść ale tak jak patrzę to singletony powinny wystarczyć bo ta biblioteka odpowiedzialna za komunikację SIP chyba sama sobie tworzy wątki i taki obiekt może działać w tle.
Randies, spróbowałem zaimplementować Twoją propozycję singletona i mogę teraz utworzyć właśnie taki obiekt - dzięki :)
ale mam kolejny problem, bo chcę w rożnych metodach odwoływać się do tego obiektu i jakoś mi to nie wychodzi.
powiedzmy że mam coś takiego

void CSIPTSPLine::InitAddress(CTSPIAddressInfo* pAddress)
{

// w pewnym momencie tworze mój obiekt
Screen first = ScreenObject::create();

}


CSIPTSPLine::~CSIPTSPLine()
{

/*a tu chciałbym wywołać kod destruktora dotyczącego mojego singletowego obiektu,
ale jak chcę odwołać się do first'a to go nie znajduje, a jak tworze kolejny obiekt i na jego rzecz
chcę wywołać destruktor singletonowy to wygląda to trochę na inny obiekt */

}


bool CSIPTSPLine::OnMakeCall(RTMakeCall* pRequest)
{

// tutaj też bym chciał coś zrobić na rzecz stworzonego obiektu
}

może coś pomieszałem w tym,że wcisnąlem kod odpowiedzialny za komunikację SIP do konstruktora? Lepiej wepchnąć go do oddzielnej metody w singletonie?

Pozdrawiam

0

Hej,
Jeszcze walczę ze swoimi problemami ale myślę, że wątki mogą mi się przydać. Spróbowałem wklepać kawałek kodu Ranidesa:

// To będzie hulało w tle 
DWORD WINAPI some_code(void*) {
    _TSP_DTRACE(" -- 2 -- "); // funkcje biblioteki -  wypisują komunikat 
      return 0;
    }

no i dostaję kilka błędów w stylu:
makecall.obj : error LNK2005: "unsigned long __stdcall some_code(void *)" (?some_code@@YGKPAX@Z) already defined in dropcall.obj

wiem,że to wina kompilacji rożnych bibliotek(nie wiem czy dobrze to określam) i zastanawiam się czy może tą "wielowątkowość" można by załatwić lepiej tzn. wydaje mi się że może coś dopasowanego do charakteru dll - przemknęła mi biblioteka Boost i jej opcje wielowątkowości - ale się nie jestem pewien.

0

to nie ma ani z wielowątkowością nic wspólnego, ani z boostem, ani z DLL ;> Po prostu zdefiniowałeś metodę kilka razy - innymi słowy wstawiłeś to w pliku .h, zamiast w .c / .cpp W pliku .h ma być tylko deklaracja.

Co do destruktora, na stare pytanie odpowiadając.

  1. boże jedyny, a po co ty chcesz jawnie wołać destruktor obiektu? Sam się zniszczy, jak przyjdzie jego czas - singleton zniszczy się podczas zakończenia programu / zwolnienia DLL-ki

  2. jak "tworzysz kolejny obiekt", to jest to ten sam obiekt. Wygląda na inny, bo pewnie patrzysz źle ;p Ewentualnie coś skopałeś w singletonie (w funkcji create zapomniałeś o static :? )

1 użytkowników online, w tym zalogowanych: 0, gości: 1