ANSI C Bibliothek zum Auslesen der an das Programm übergebenen Parameter



  • bibliothekar schrieb:

    Kann man in C Funktionen "verriegeln" (Mutex, Semaphor, ...) usw ... und weiss jemand wie?

    das geht. wenn du z.b. windoofs benutzt: http://msdn2.microsoft.com/en-us/library/ms682530.aspx
    🙂



  • hast du globale daten/objekte in deinen bibs ?



  • jepp schrieb:

    hast du globale daten/objekte in deinen bibs ?

    also ich habe, nachdem was ich hier so gelernt habt, die Daten modulglobal mit static gekapselt und der Zugriff von außen erfolgt über entsprechende "getter" und "setter" Funktionen.

    Ist das dann in deinem Sinn "global"?

    Den link zum Repository habe ich ja gepostet und noch ne Anmerkung, das ist natürlich ein zehn Minuten Projekt, als Antwort auf das Ursprungsposting.



  • concurrent-freak schrieb:

    bibliothekar schrieb:

    Kann man in C Funktionen "verriegeln" (Mutex, Semaphor, ...) usw ... und weiss jemand wie?

    das geht. wenn du z.b. windoofs benutzt: http://msdn2.microsoft.com/en-us/library/ms682530.aspx
    🙂

    toll 🙂 das ist ja einfach:

    // Request ownership of the critical section.
    EnterCriticalSection(&CriticalSection); 
    
    // Access the shared resource.
    
    // Release ownership of the critical section.
    LeaveCriticalSection(&CriticalSection);
    

    laut MSDN Beschreibung: Declared in Winbase.h; include Windows.h.
    Scheint eine Microsoft Lösung zu sein.

    Gibt´s eine ANSI C Variante?



  • bibliothekar schrieb:

    Gibt´s eine ANSI C Variante?

    nein. Mutual Exclusion wird vom OS garantiert also musst du mit den Mitteln arbeiten, die dir dein OS zur Verfügung stellt. Unter Posix Systeme wie Linux wäre dann

    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL);
    ...
    /* enter critical region */
    pthread_mutex_lock(&mutex)
    ...
    pthread_mutex_unlock(&mutex);
    
    /* non-critical region */
    


  • bibliothekar schrieb:

    hast du globale daten/objekte in deinen bibs ?

    also ich habe, nachdem was ich hier so gelernt habt, die Daten modulglobal mit static gekapselt und der Zugriff von außen erfolgt über entsprechende "getter" und "setter" Funktionen.

    Ist das dann in deinem Sinn "global"?
    Ja, das ist verdammt global und ein Multithread-Killer.

    bibliothekar schrieb:

    Kann man in C Funktionen "verriegeln" (Mutex, Semaphor, ...) usw ... und weiss jemand wie?

    Wenn du deine Objekte/Variablen auf dem Stack erzeugst und zurückgibst, brauchst du dir keine Gedanken über Threadsicherheit zu machen.
    Jeder Thread hat seinen eigenen Stack.
    Ein Thread ruft deine Funktion auf, Thread und Funktion bilden einen gemeinsamen Stackrahmen mit den Paramatern und den lokalen Variablen. Damit sind die Daten vor Zugriffen anderer Threads geschützt.

    Bei kleinen Objekten/Variablen bis ≈ 1 MB sollte das problemlos funktionieren. Werden die Objekte zu groß, wird sich dein Compiler mit einem Stackoverflow melden.
    Eine Variable auf dem Stack zu erzeugen heisst ja nichts anderes, als sie lokal in der Funktion zu deklarieren und zu verwenden.

    Für größere Objekte kann man den Heap benutzern ( malloc, calloc ).



  • die Frage nach der Globalität der Daten habe ich wohl fehlinterpretiert. Modulglobal sind so Sachen wie

    static char * logfile;
    static int loglevel;
    

    aber die Daten, um die es eigentlich geht, sollen in *logfile geschrieben werden

    void logmsg(char * string, ...)
    {
       // bißchen Vorarbeit   
       va_start(argzeiger,string);
       vsprintf(buffer, string,argzeiger);
       va_end(argzeiger);
       s = fopen(logfile);
       fprintf(s, "%s", buffer);
       fclose(s);
       return;
    }
    

    Wenn man jetzt das logmsg Modul als statische Bibliothek kompiliert und in ein anderes Programm, nennen wir es use_log, linkt, das mit mehreren Threads parallel logmsg() nutzen will, muss ich doch logmsg() schon "verriegeln", oder?

    Verständnisfrage: was passiert, wenn ich das logmsg-Modul als dynamische Bibliothek erstelle mit char * logfile usw.? Dann könnten doch verschiedene Programme die logmsg - Modul Funktion setLogfile(char *l); aufrufen.
    Sagen wir Prg A und Prg B nutzt die logmsg() Funktionen der logmsg.dll.
    Prg A ruft

    setLogfile("/tmp/a.log");
    logmsg("ich bin Prg A\n");
    

    auf und Prg B:

    setLogfile("/tmp/a.log");
    logmsg("ich bin Prg B\n");
    

    auf.

    Geht sowas? Also, wer stellt da wie sicher, dass Prg A nach a.log und Prg B nach b.log schreibt?



  • bibliothekar schrieb:

    Wenn man jetzt das logmsg Modul als statische Bibliothek kompiliert und in ein anderes Programm, nennen wir es use_log, linkt, das mit mehreren Threads parallel logmsg() nutzen will, muss ich doch logmsg() schon "verriegeln", oder?

    Im Prinzip müsstest du static char * logfile; sperren, wie auch immer du das anstellst.

    Du kannst dir das ganze Klimbim sparen:

    int logmsg( char * logfile, char * string, ...)
    

    bibliothekar schrieb:

    Verständnisfrage: was passiert, wenn ich das logmsg-Modul als dynamische Bibliothek erstelle mit char * logfile usw.?

    Das ist das gleiche Problem, nur in grün.
    http://bcb-tutorial.c-plusplus.net/DLL_Tutorial/artikel7.html

    bibliothekar schrieb:

    Geht sowas? Also, wer stellt da wie sicher, dass Prg A nach a.log und Prg B nach b.log schreibt?

    So:
    int logmsg( char * logfile, char * string, ...)

    Oder warum zum Kuckuck muss die Variable logfile unbedingt global sein ? 😕



  • naja, zum einen ist das bei Aufrufen der Funktion unkomfortabler, da man ja immer das Logfile mit übergeben muss und zum anderen ist es ja auch denkbar, dass logmsg das logfile im init() exklusiv öffnet und im shutdown() wieder schliesst, um sich das dauernde fopen(), fclose() zu sparen.



  • was ist denn einfacher, getter-, setterfunktionen aufrufen, threads sperren.
    oder einfach nur einen parameter mehr übergeben.

    sollten mehrere threads deine funktion nutzen wollen, müssten alle warten, bis das programm durch ist.
    das ist doch nicht in deinem sinne denke ich mal.



  • ich hab´s noch nicht ganz, auch wenn´s mir nicht gefällt, das logfile an logmsg() immer zu übergeben, ich finde es sieht dümmlich aus, den von der Logik her eigentlich immer gleichen Wert an eine Funktion als Parameter zu übergeben und natürlich ist es auch mehr Aufwand, weil die in der Bibliothek angebotenen logging-Funktionen, muss man ja nur einmal ausprogrammieren, genutzt werden sie dann ja manigfaltig.
    Aber sei´s drum, akzeptiert:

    int logmsg(char * logfile, char * msg)
    

    einverstanden. Beim int loglevele habe ich das Problem ja wieder.
    Der Nutzer der logmsg - Bibliothek würde ja erwarten, dass er in seinem Programm mit setLoglevel(int level) den Loglevel für sich setzen kann und die logmsg() aus der Bibliothek auch nur dann protokolliert, wenn der gesetzte loglevel > als der übergebene ist. Und diese Logik

    int logmsg(char * logfile, int level, char * msg) {
     if (loglevele < level)
     { 
       fprintf("%s", msg);
     }
     else
     {
       // nichts an dieser Stelle 
     }
     ...
    

    dann auch noch jedes Mal, und man bedenke, das oben ist natürlich nur ein Fragment, in der Realität würde ja noch einiges mehr if-then gemacht werden, selbst in sein Programm aufnehmen zu müssen, würde wohl nicht akzeptiert werden und außerdem, würde das ja eine echte Sinnfrage für die logmsg - Bibliothek bedeuten, da sin dadurch dann ja tatsächlich, wie ganz am Anfang schonmal vorgeschlagen, zu einem bloßen fprintf verkommen würde.

    Es muss eine andere Lösung geben.



  • wozu soll denn der loglevel sein ? was soll überhaupt protokolliert werden ?
    wie wäre es mit sowas:

    struct Log
    {
    char * logfile;
    int level;
    // ...
    }

    struct Log* Init( char* logfile, int level )
    {
    struct Log* log = malloc(...
    Log->level = level;
    ...

    return log;
    }

    void Close( struct Log* log )
    {
    if ( log ) free (log);
    }



  • der struct log Hinweis war der gedankliche Durchbruch. Gleich mal umgesetzt und damit sollte dann logmsg auch DLL-fähig sein 🙂
    Thanx



  • bibliothekar schrieb:

    der struct log Hinweis war der gedankliche Durchbruch. Gleich mal umgesetzt und damit sollte dann logmsg auch DLL-fähig sein 🙂
    Thanx

    👍



  • die Idee mit dem struct, um die logmsg Bibliothek DLL-fähig zu machen klang gut.
    logmsg.h

    struct Log {
    	char * logfile;
    	int loglevel;
    	char * version;
    	int logdevice;
    };
    

    Wie vorgeschlagen gibt es die entsprechenden Init() und Close() Funktionen. Klappt auch, aber meine eigentlich angestrebte Datenkapselung blieb dabei auf der Strecke 😞
    Wenn ich in einem anderen Programm die Bibliothek nutzen will, würde das momentan so:
    use_logmsg.c

    ...
            struct Log * l;
    	l = lm_Init("c:\\temp\\inst.log", LM_TRACE, LM_DEVICE_FILE);
    	lm_msg(l, LM_INFO, "Hallo Welt!");
    ...
    

    aussehen.
    Unglücklicherweise ist in dieser Implementierung wieder sowas wie:use_logmsg.c

    ... 
            l->loglevel = 4711;
    ...
    

    möglich. Was ich ja ganz ursprünglich durch

    static loglevel
    

    verhindert habe.

    Was muss ich tun, um die Variablen des structs Log vor dem Zugriff von aussen zu schützen?



  • wenn ich die hier in dem Community - Thread erarbeitete Übungs-Bibliothek aus einem anderen Projekt in Visual Studio 2005 Express verwenden, was funktioniert, bekomme ich folgende Linker Warnung:

    LINK : warning LNK4098: Standardbibliothek "LIBCMTD" steht in Konflikt mit anderen Bibliotheken; /NODEFAULTLIB:Bibliothek verwenden.
    

    Den jeweils aktuellen Code gibt unter:
    http://opensvn.csie.org/c_cpp_programming_sources/logmsg/
    bzw. wie die Bibliothek eingebunden wird:
    http://opensvn.csie.org/c_cpp_programming_sources/use_logmsg/

    Kann ich bei einer derartigen Fehlermeldung noch ruhig schlafen?



  • Sorry, ich nutze den schönen Sonntag gerade auf dem Balkon und da ergeben sich halt Fragen 😉

    nachdem ich die Funktion lm_msg derart geändert habe, dass der Loglevel mit übergeben werden kann, meckert der Compiler alle Stellen im Code an, die noch die alte Syntax verwenden (lm_msg zu wenige Parameter ...)

    Das jetzt zu ändern ist natürlich mühsam.

    Kann ich eine Funktion auch überladen? Soll heissen, so schreiben, dass sie sowohl den Aufruf

    lm_msg(l, LM_ERROR, "hallo welt");
    

    wie auch

    lm_msg(l,  "hallo welt");
    

    unterstützt?


Anmelden zum Antworten