strcpy und struct



  • Hi,
    Ich arbeite bei threads mit structs und caste es dann in den threads um die daten zu verwenden.
    Doch wenn ich mit strcpy im main thread ein char array auf das char array im struct schreibe, dann stürtzt das Programm ab. Meine Frage ist, warum ist das so und wie kann ich es anders machen?

    MFG ReduX



  • Nichts aus der Standardbibliothek ist thread-safe. Da musst Du den Zugriff auf das Array synchronisieren.



  • Hi,
    Ja aber es sind doch verschiedene Adressen Bsp.:

    struct data {
    int id;
    };
    void thread(void* arg)
    {
    int i = static_cast<data*>(arg)->id;
    printf("%d",i);
    }
    int main(void) {
    while(1) {
    if(event) {
    data forthread;
    forthread.id = 4;
    pthread_t t2;
    pthread_create(&t2,0,(void*)thread,&forthread);
    }
    }
    }
    

    Jedesmal wenn er einen neuen struct anlegt ist es doch automatisch eine andere Adresse im Speicher. Außerdem wenn es nicht thread save wäre dann würde es im Prinzip ja nur den Inhalt ändern?!? Aber das Programm stürtzt ja ab.

    MFG ReduX



  • Du musst den Gültigkeitsbereich der Variablen beachten. In deiner Schleife wird immer wieder die Variable "forthread" auf dem Stack erstellt und ein Zeiger darauf dem Thread übergeben. Direkt nachdem der Thread gestartet wurde, wird die Variable "forthread" sofort wieder zerstört, da der Block und damit die Lebenszeit dieser Variable endet. Die Variable ist also weg, der Zeiger darauf ungültig.



  • Hi,
    Danke für deine Antwort.
    Wie meinste wie ich das Problem am optimalsten löse?
    Sollte ich einen globalen struct machen, und diesen vor dem thread start mit daten füttern und dann im thread in eine lokale Variable lesen? Reicht dort die Zeit bevor die Hauptschleife wieder an der if Abfrage ist?

    MFG ReduX



  • Du könntest die Variable mit "new" auf dem Heap erstellen und dem Thread übergeben. Wenn der Thread mit der Ausführung fertig ist, wendet er "delete" drauf an.
    Ich weiß nicht, ob das optimal oder eben sogar am optimalsten ist (:D), aber ich würde keine Abschätzung machen, wie lange es dauern könnte, bis der Thread sich selbst ne Kopie von der Variablen gemacht hat oder so 🙂



  • Hi,
    Kannst du mir sagen ob ich das so richtig mache?(Habe es mit den Adressen nicht so):

    struct data {
      int id;
      char* buffer;
    };
    void thread(void* arg)
    {
    int i = static_cast<data*>(arg)->id;
    int size = strlen(static_cast<data*>(arg)->buffer);
    char* buf = new char[size+1];
    strcpy(buf,static_cast<data*>(arg)->buffer);
    //blablabla
    delete [] buf;
    //lösche struct:
    delete [] &arg; // Ist das so richtig? 
    }
    int main(void)
    {
    //blabla
    data* ver = new data;
    ver.id = i;
    // starte ptherad und übergebe adresse
    }
    

    MFG ReduX



  • Aufräumen;

    struct thread_data_t
    {
        unsigned int id;
        char* data;
    
        thread_data_t(const char* string = NULL, const unsigned int id = 0)
            : data(new char[std::strlen(string)]()), id(id)
        {
            std::strcpy(data, string);
        }
        ~thread_data_t()
        {
            delete [] data;
        }
    };
    
    void thread(void* ptr_arg)
    {
        thread_data_t* ptr_data(static_cast<thread_data_t*>(ptr_arg));
    
        // copy data
        const unsigned int id(ptr_data->id);
        char* data(new char[std::strlen(ptr_data->data) + 1]());
        std::strcpy(data, ptr_data->data);
    
        // TODO: Do something!
    
        delete [] data;
    }
    
    int main()
    {
        thread_data_t* ptr_data(new thread_data_t("Test", 10));
        thread(ptr_data);
        delete ptr_data;
    }
    

    was du da machen wolltest geht nicht, da du nicht einen void-Zeiger löschen kannst, weil dieser keine Größe hat!



  • ReduX schrieb:

    ...optimalsten...

    Oh Oh Oh ... wenn ich da nicht mal wieder 4 Seiten Germanistik-Diskussion heranrauschen höre !!! 😉

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Oh Oh Oh ... wenn ich da nicht mal wieder 4 Seiten Germanistik-Diskussion heranrauschen höre !!! 😉

    Gruß,

    Simon2.

    Och, der Link zu den anderen 8 Seiten von neulich würd doch schon reichen ^^



  • Hi,
    Danke für deine Antwort!
    Der Code läuft soweit nur stürtzt das Programm ab.
    Ich denke es liegt daran:

    int main()
    {
        thread_data_t* ptr_data(new thread_data_t("Test", 10));
        thread(ptr_data);
        delete ptr_data; // Im thread wurden die Daten wahrscheinlich nochnicht rauskopiert!
    }
    

    Kann ich statt im main die daten auch im thread löschen?

    MFG ReduX



  • ja ... aber am saunbersten wäre es, wenn du auf den Thread warten würdest ...



  • Tag,
    Also das Problem ist dabei das der main thread an einen Port gebunden ist und auf clients horcht. Ich übergebe dann wenn einer Connected die id an den thread um weiter zu verfahren. Da kann ich nicht warten weil sonst würde der ganze Server blockieren. Bzw. was ist daran nicht sauber? gibts dadurch speicherleaks oder so?

    MFG ReduX



  • ReduX schrieb:

    Bzw. was ist daran nicht sauber? gibts dadurch speicherleaks oder so?

    Normalerweise sollte derjenige Teil, der den Speicher anfordert, ihn auch wieder freigeben. In diesem Fall ist es meiner Meinung nach aber ok, wenn der Haupthread den Speicher anfordert und der gestartete Thread ihn wieder freigibt. Dürfte auch keine Speicherlecks geben, also von daher alles ok.

    Wenn du nur einen Wert übergeben willst und sizeof(Wert)<=sizeof(void*) gilt, dann kannst du deinen Wert auch zu einer Adresse casten, der Thread castet den void-Zeiger wieder auf den Wert um und du brauchst keinen Speicher zu allokieren/freizugeben.



  • Hi,
    Danke für deine Antwort.
    Das Problem ist ich weiß nicht wie ich es im Thread mit delete löschen soll.
    Habe mit Adressen irgendwie Probleme weil in void*arg steht ja die Adresse drin aber warum geht dann "delete arg" nicht?

    MFG ReduX



  • Weil es ein void-Pointer ist. Und was soll er denn dann dort löschen wo der Zeiger hinzeigt? Void/nichts?



  • Hi,
    Irgendwie stürtzt das Programm immer noch ab. Hier der Vorab Code(Patchwork):

    struct data
    {
        unsigned int id;
        char* info;
    
        data(const char* string = NULL,const unsigned int id = 0) : info(new char[strlen(string)]),id(id)
        {
            strcpy(info, string);
        }
        ~data()
        {
            delete [] info;
        }
    };
    void verification(void* arg)
    {
    data* ptr_data(static_cast<data*>(arg));
    unsigned int i(ptr_data->id);
    int size = strlen(ptr_data->info);
    char* buffer = new char[size+1];
    strcpy(buffer,ptr_data->info);
    printf("ID: %id, Buffer: %s",i,buffer);
    delete [] buffer;
    }
    int main()
    {
    while(1) {
    if(event) {
    data* ver(new data("TestTest",32));
    _beginthread(verification,0,&ver);
    }
    }
    }
    

    MFG ReduX



  • new char[strlen(string)]
    =>
    new char[strlen(string)+1]

    Oder einfach std::string verwenden...

    und darf man fragen, wieso du Variablen so data* ver(new data("TestTest",32)); initialisierst, anstatt data* ver = ... ?



  • #include <cstring> // std::strcpy, std::strlen
    #include <iostream> // std::cout, std::endl
    
    struct data
    {
        unsigned int id;
        char* info;
    
        data(const char* string = NULL, const unsigned int id = 0) 
            : info(new char[std::strlen(string) + 1]()), id(id) // hier + 1 bei info-initialisierung, da sonst Nullterminierung fehlt!
        { std::strcpy(info, string); }
    
        ~data()
        { delete [] info; }
    };
    
    void verification(void* arg)
    {
        data* ptr_data(static_cast<data*>(arg));
    
        // const, du veränderst nichts mehr an der id!
        const unsigned int id(ptr_data->id);
        // const, denn auch die Größe veränderst du nicht ;)
        const std::size_t size(std::strlen(ptr_data->info) + 1);
        char* buffer(new char[size]);
        std::strcpy(buffer, ptr_data->info);
    
        std::cout << "ID: " << id << ", Buffer: " << buffer << std::endl;
    
        delete [] buffer;
    }
    
    int main()
    {
        while(1) 
        {
            if (event) 
            {
                data* ver(new data("TestTest", 32));
                ::_beginthread(verification, 0, ver); // WARUM &ver? ver ist schon ein Zeiger!
            }
        }
    }
    

    Aber einfacher:

    #include <string>
    
    void verification(void* arg)
    {
        data* ptr_data(static_cast<data*>(arg));
        std::cout << "ID: " << ptr_data->id << ", Buffer: " << ptr_data->info << std::endl;
    }
    

    ... 😉



  • Oder eben mit strings (!!)

    #include <cstring> // std::strcpy, std::strlen
    #include <iostream> // std::cout, std::endl
    #include <string> // std::string
    
    struct data
    {
        unsigned int id;
        std::string info;
    
        data( const std::string str="", const unsigned int id=0 ) : info(str), id(id)
        { }
    };
    
    void verification( void* arg )
    {
        data* my_data = reinterpret_cast<data*>( arg );
        std::cout << "ID: " << my_data->id << ", Buffer: " << my_data->buffer << std::endl;
        delete my_data;
    }
    
    int main()
    {
        while(1)
        {
            if (event)
            {
                ::_beginthread( verification, 0, new data("TestTest",32) );
            }
        }
    }
    

Anmelden zum Antworten