CStdioFile - Zugriff von mehreren Threads



  • Hi,

    ich habe ein .txt file, das während der ganzen Laufzeit geöffnet ist.

    ich öffne es in main. dann starte ich noch weitere threads die auch darauf zugreifen. Jeder soll eine Zeile einlesen und weiter verarbeiten.

    wenn ich 20 threads benutze, funktioniert es, wenn ich es mit ~100 versuche, bekomme ich einen error: "Die Anweisung in 0x7c... verweist auf den Speicher 0x0.... Der Vorgang "read" konnte nicht auf dem Speicher durchgeführt werden."

    Wie kann man das lösen?

    Danke schonmal

    Popogas



  • Hi,

    das liegt nicht daran, das du 20, 100 oder 2 Threads hast. Wenn mehrere Threads
    auf ein Objekt zugreifen und du den Zugriff nicht syncronisierst, spielst
    du russisches Roulette!

    Du must den Zugriff auf das CStdioFile-Objekt Syncronisieren. Schau dir
    dazu die Klasse CCriticalSection in der MSDN an.

    Gruss
    EB



  • Ok danke.
    Hab mir das alles mal in der msdn angeschaut und durchgelesen.
    ich hab es theoretisch verstanden.
    Es gibt nurnoch ein problem, ich weiß nicht wie ich es initialisiere.

    Im folgenden Codebeispiel wird diese Methode anhand des m_CritSection-Datenmembers (vom Typ CCriticalSection) demonstriert, das in der gemeinsam genutzten Ressourcenklasse deklariert wurde;

    (http://msdn.microsoft.com/library/deu/default.asp?url=/library/DEU/vccore/html/_core_multithreading.3a_.how_to_use_the_synchronization_classes.asp)
    das steht in der msdn.

    Welches ist die Ressourcenklasse?

    bzw kann vllt jemand n ganz kurzes codebeispiel geben, das wär super 🙂

    sry für diese noobigen fragen, aber ich sitz da schon länger dran, und habs noch nich geschafft.



  • Hi,

    du kannst eine Klasse von CStdioFile ableiten z.B CSharedFile.
    Darin machst du eine protected Member Varialble vom Typ CCriticalSection.
    Die wird im Konstruktor initialiert und im Destruktor zerstört.
    In den Konstruktor und den Destruktor natürlich die Basis-Konstruktoren bzw.
    Destruktoren aufrufen.
    Dann implementierst du alle Methoden von StdioFile, welche du benötigst.
    Dann "lockst" du das CriticalSection objekt, rufst die entsprechende Funktion
    in der Basisklasse auf, "delockst" das Objekt und gibst die Rückgabe der Funktion zurück.
    Du kapselst also jede public Funktion die du benötigst. Du solltest daher
    deine Klasse protected von CStdioFile ableiten statt public.
    Damit ist dann die Klasse Threadsicher.

    Ich hoffe das hilft weiter. Sonst Poste deinen Code wenn du nicht weiter kommst.

    Gruss
    EB



  • Danke schonmal.

    ich denk das schaffe ich so, ist ja ne relativ genaue beschreibung.
    ich melde mich nochmal wenn ich noch n problem hab, oder poste hier mal mein code.
    man findet net so viele gute beispiele dazu



  • ich habs mit hilfe von dem msdn beispiel versucht.

    scheint aber noch nicht ganz zu stimmen, ich bekomme immer "programm hat ein fehler festgestellt, muss beendet werden" beim starten.

    class CSharedFile
    {
    	  static CCriticalSection    m_cs;
    	  static CStdioFile inputfile;
    
    public:
        CSharedFile(void);
    static CString leseString();
    	~CSharedFile(void);
    
    };
    
    CStdioFile CSharedFile::inputfile;
    CCriticalSection CSharedFile::m_cs;
    
    CString CSharedFile::leseString()
    {
    	m_cs.Lock();
    	CString str;
    	inputfile.ReadString(str);
    	m_cs.Unlock();
    	return str;
    }
    

    aus einer anderen funktion dann ->

    while(sIP = CSharedFile::leseString() )
    		{	
                          // do sth
    
    		}
    

    hab dabei bissel hier geschaut: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_mfc_ccriticalsection.3a3a.lock.asp



  • Hi,

    hier mal ein Ansatz:

    Header:

    #pragma once
    
    #include <afxmt.h>	// mfc sync object
    
    class CAutoLock // Hilfsklasse für CriticalSection
    {
    public:
    	CAutoLock(CCriticalSection& cs); // Lock Objekt
    	~CAutoLock(); // Unlock Objekt 
    
    private:
    	CCriticalSection& m_cs; // reference auf Lock-Objekt
    };
    
    // CSafeStdioFile command target
    
    class CSafeStdioFile : protected CStdioFile // protected ableiten, damit Client nur unsere Threadsicheren Methoden aufrufen kann!
    {
    public:
    	CSafeStdioFile(FILE* pOpenStrem);
    	CSafeStdioFile(LPCTSTR lpszFileName, UINT nOpenFlags);
    	virtual ~CSafeStdioFile();
    
    	virtual LPTSTR ReadString(LPTSTR lpsz, UINT nMax);
    	virtual BOOL ReadString(CString& rString);
    
    protected:
    	CCriticalSection m_cs; // Lock Objekt
    };
    

    Implementierung:

    // SafeStdioFile.cpp : implementation file
    //
    
    #include "stdafx.h"
    #include "SafeStdioFile.h"
    
    // CAutoLock
    CAutoLock::CAutoLock(CCriticalSection& cs)
    : m_cs(cs)
    {
    	m_cs.Lock();
    }
    
    CAutoLock::~CAutoLock()
    {
    	m_cs.Unlock();
    }
    
    // CSafeStdioFile
    
    CSafeStdioFile::CSafeStdioFile(FILE* pOpenStream)
    : CStdioFile(pOpenStream)
    {
    }
    
    CSafeStdioFile::CSafeStdioFile(LPCTSTR lpszFileName, UINT nOpenFlags)
    : CStdioFile(lpszFileName, nOpenFlags)
    {
    }
    
    CSafeStdioFile::~CSafeStdioFile()
    {
    }
    
    // CSafeStdioFile member functions
    LPTSTR CSafeStdioFile::ReadString(LPTSTR lpsz, UINT nMax)
    {
    	CAutoLock lock(m_cs); // lock die Section
    
    	return CStdioFile::ReadString(lpsz, nMax); // Rufe Basisklasse auf
    
    // CAutoLock wird zerstört und gibt die Section wieder frei!
    }
    
    BOOL CSafeStdioFile::ReadString(CString& rString)
    {
    	CAutoLock lock(m_cs);
    
    	return CStdioFile::ReadString(rString);
    }
    

    Gruss
    EB



  • Ok danke hab es in mein prog eingebaut.

    stimmt es wenn ich es dann so aufrufe:

    CSafeStdioFile inputfile;
    ...
    inputfile.Open(input, CFile::modeRead | CFile::shareDenyNone); // die Openfunktion hab ich noch reingepackt
    ...
    inputfile.ReadString(str);
    ...
    

    aber irgendwas stimmt da noch nicht 😕 er stürt gleich ab, "programm muss beendet werden"...


Anmelden zum Antworten