QList mach immernoch Probleme

Alles rund um die Programmierung mit Qt
Antworten
bw1faeh0
Beiträge: 94
Registriert: 10. Oktober 2007 14:48
Wohnort: Braunschweig

QList mach immernoch Probleme

Beitrag von bw1faeh0 »

Guten Morgen,

ich habe derzeit immer noch Probleme bei der Verwendung von QLists.
Ich habe ja schon seit einer Weile vermutet, dass mein Programm wegen dieser QList abstürtzt.
Nun hat es mir der gdb bestätigt:
Previous frame inner to this frame (corrupt stack?)
Previous frame inner to this frame (corrupt stack?)
warning: HEAP[fmbMonitor.exe]:
warning: Invalid allocation size - d11515f0 (exceeded 7ffdefff)

warning: QList: Out of memory
Bei meiner QList handelt es sich um eine Liste vom Typ
QList <unsigned char>, die eine Membervariable der Klasse ist.
Im Konstruktor dieser Klasse wird lediglich ein list.clear() aufgerufen.

Anschließend füge ich in einer sich regelmäßig wiederholenden Methode mit dem <<-Operator eine unbestimmte Anzahl neue Bytes (auch in Form einer QList<unsigend char> hinzu.

Am Ende der Methode entferne ich die Bytes, die aus der Liste verarbeitetet wurden, mit while(bedingung){list.removeFirst()}.

Ist an diesem Vorgehen irgend etwas flasch? Warum bekomme ich die Fehlermeldung 'out of Memory'?

Mit freundlichen Grüßen

Christian
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Ohne code wird das nichts.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
bw1faeh0
Beiträge: 94
Registriert: 10. Oktober 2007 14:48
Wohnort: Braunschweig

Beitrag von bw1faeh0 »

Ok, dann hier der Quellcode:

class FmbSniffer: erstellt ein Objekt zur Kommunikation mit der Hardware, ein Thread zum Auslesen der Hardware und ein Thread zum Weitersenden der Daten:

Code: Alles auswählen

class FmbSniffer:public QObject
{
	Q_OBJECT
public:
	FmbSniffer();
	~FmbSniffer();

	SendThread	*sendToView;
	PollThread	*pollFmbSniffer;
	
	FTDI *ftdi;
	
	signals:
	void updateStatusTip(QString);
	void ping();
	
	
	
	
public slots:
	bool getDeviceStatus();
	void pingSlot();
	void sendFilterToDevice(QList<unsigned char>);
	
private:
	
	QTimer			*deviceStatusTimer;
	QList<FmbData*>	*telegramList;
	QMutex			*mutex;
};

Code: Alles auswählen

FmbSniffer::FmbSniffer()
{
	telegramList = new QList<FmbData*>;
	mutex = new QMutex;
	
	//	Erzeugen eines neuen FTDI-Objekts zur Kommunikation mit dem FTDI-Chip der Hardware
	ftdi = new FTDI();
	
	pollFmbSniffer = new PollThread(telegramList, mutex, ftdi);
	pollFmbSniffer->start();
	
	connect(pollFmbSniffer, SIGNAL(ping()), this, SLOT(pingSlot()));
		
	sendToView = new SendThread(telegramList, mutex);
	sendToView->start();
	
	connect(sendToView, SIGNAL(ping()), this, SLOT(pingSlot()));
	
	deviceStatusTimer = new QTimer();
	deviceStatusTimer->setInterval(c_OPEN_CONNECTION_INTERVALL);
	deviceStatusTimer->start();
	connect(deviceStatusTimer, SIGNAL(timeout()), this, SLOT(getDeviceStatus()));
}

FmbSniffer::~FmbSniffer()
{
}

void FmbSniffer::pingSlot()
{
	emit ping();
}

bool FmbSniffer::getDeviceStatus()
{
	
	
	if (!ftdi->isInterfaceConnected())
	{	//	Wenn die Schnittstelle nicht geöffnet ist
		
		//	Schnittstelle öffnen
		ftdi->Open();
		
		if (ftdi->isInterfaceConnected() == true)
		{	//	Wenn die Schnittstelle erfolgreich geöffnet wurde
			
			if (ftdi->isSnifferConnected() == true)
			{	//	wenn der Hitachi hinter der Schnittstelle gefunden wurde
				emit updateStatusTip("FM-Sniffer verbunden");
				return true;
			}
			else
			{
				emit updateStatusTip("USB-Schnittstelle geöffnet, FM-Sniffer nicht verbunden");
				return false;
			}
		}
		else
		{	//	Für den Fall, dass die Schnittstelle nicht geöffnet werden konnte
			emit updateStatusTip("USB-Schnittstelle konnte nicht geöffnet werden");
			return false;
		}
	}
	else
	{
		if (pollFmbSniffer->nothingReceived > 150)
		{	//	Wenn 1,5 Sekunden lang nichts mehr empfangen wurde wird überprüft ob der Hitachi noch da ist
			
			if (ftdi->isSnifferConnected() == true)
			{	//	wenn der Hitachi hinter der Schnittstelle gefunden wurde, true zurück geben
				emit updateStatusTip("FM-Sniffer verbunden");
				return true;
			}
			else
			{	//	der Hitachi antwortet nicht mehr...
				emit updateStatusTip("USB-Schnittstelle geöffnet, FM-Sniffer nicht verbunden");
				return false;
			}
		}
		else
		{	//	Der Empfang der letzen Daten ist weniger als 1,5 Sekunden her
			emit updateStatusTip("FM-Sniffer verbunden");
			return true;
		}
	}
}

void FmbSniffer::sendFilterToDevice(QList<unsigned char> filterDaten)
{
	//	Erstellung eines Arrays auf dem Heap, dass die Listdaten enthalten wird
	unsigned char* data= new unsigned char[filterDaten.count()];
	
	//	Füllen des Arrays mit den Daten aus der Liste
	for (int i_liste = 0; i_liste < filterDaten.count(); i_liste++)
	{
		data[i_liste] = filterDaten.at(i_liste);
	}
	
	//	Übergabe des Arrays an das Device-Objekt
	ftdi->SendData(data, filterDaten.count());
	
	delete data;
}
class PollThread liest von der Hardware und fügt die gelesenen Daten einer QList zu, die die gelesenen Daten puffern soll

Code: Alles auswählen

class PollThread:public QThread
{
	Q_OBJECT
public:
	PollThread(QList<FmbData*> *usedTelegramList, QMutex *usedMutex, Communication *communicationDevice);
	~PollThread();
	
	void start();
	
	//	Zeit seit dem letzen Empfang eines Bytes
	unsigned int nothingReceived;
	
	signals:
	void ping();
	void updateStatusTip(QString);
	
private slots:
	void readFromHardware();

private:
	void insertIntoNewTelegram(unsigned char, int);
	
	
	Communication			*device;
	QList<unsigned char>	receivedBytes;
	QList<FmbData*>			*telegramList;
		
	//unsigned long i_list;		
	QTimer	*pollTimer;
	FmbData *newTelegram;
	QMutex	*mutex;
	
	unsigned short i_receivedByte;
	bool lastByteWasFF;
	
	
protected:
	void run();
};


Code: Alles auswählen

PollThread::PollThread(QList<FmbData*> *usedTelegramList, QMutex *usedMutex, Communication *communicationDevice)
{
	telegramList = usedTelegramList;
	//	Verwendung eines Mutex, um den Zugriff auf die Message-Liste zu verwalten
	mutex = usedMutex;
	device = communicationDevice;
	receivedBytes.clear();
	
	i_receivedByte = 0;
	lastByteWasFF = false;
	newTelegram = new FmbData;
	
	pollTimer = new QTimer();
	pollTimer->setInterval(c_POLL_INTERVALL);
	pollTimer->start();
	connect (pollTimer, SIGNAL(timeout()), this, SLOT(readFromHardware()));
	
	
	
	nothingReceived = 0;
}

void PollThread::readFromHardware()
{
	receivedBytes << (device->GetData());

	
	//	Nach den Telegramm-Ende-0xFF suchen
	if (receivedBytes.lastIndexOf(0xFF) != -1)
	{
		newTelegram = new FmbData;
		int i_receivedByte = 0;
		
		for (int i_Liste = 0; i_Liste <= receivedBytes.lastIndexOf(0xFF); i_Liste++)
		{
			
			if ((receivedBytes.at(i_Liste) == 0xFF) and (i_Liste < receivedBytes.lastIndexOf(0xFF) and (receivedBytes.at(i_Liste + 1) == 0xFF)))
			{
				//	Das 0xFF ist ein geschützes 0xFF im Datenstrom
				
				//	Byte überspringen
				i_Liste++;
				//	nächstes Byte speichern
				insertIntoNewTelegram(receivedBytes.at(i_Liste), i_receivedByte);
				i_receivedByte++;
			}
			else if (receivedBytes.at(i_Liste) == 0xFF)
			{
				//	Das 0xFF ist ein Telegramm-Ende-0xFF
				mutex->lock();
				telegramList->append(newTelegram);
				mutex->unlock();
				newTelegram = new FmbData;
				i_receivedByte = 0;
			}
			else
			{
				//	Normales Byte im Datenstrom sichern
				insertIntoNewTelegram(receivedBytes.at(i_Liste), i_receivedByte);
				i_receivedByte++;
			}
		}
		delete newTelegram;
		
		
		//	Inhalt der Liste bis einschließlich des letzen Vorkommens von 0xFF löschen
		while(receivedBytes.lastIndexOf(0xFF) != -1)
		{
			receivedBytes.removeFirst();
		}

		//emit updateStatusTip(QString::number(receivedBytes.size()));
		
		if (receivedBytes.isEmpty())
		{	//	Speicher wieder freigeben, weil das nicht vom removeFirst() erledigt wird...
			receivedBytes.clear();
		}
		
		//	Zeit seit letzem Empfang auf Null setzten
		nothingReceived = 0;
	}
	else
	{	//	Nichts empfangen, Zeit seit dem letzem Empfang erhöhen
		nothingReceived++;
	}

	
	
}

void PollThread::insertIntoNewTelegram(unsigned char byte, int i_receivedByte)
{
	
	switch (i_receivedByte)
	{
	//	Status-Byte
	case 0:
		newTelegram->Status.BYTE = byte;

		break;
	
	//	Checksummen-Byte
	case 1:
		newTelegram->checksum = byte;
		
		break;
	
	//	High-Byte der Länge
	case 2:
		newTelegram->laenge = (WORD) (byte << 8);
		
		break;
	
	//	Low-Byte der Länge
	case 3:
		newTelegram->laenge |= (WORD) byte;
		
		break;
	
	//	Stunden-Byte
	case 4:
		newTelegram->zeit.STUNDEN = byte;
		
		break;
		
	//	Minuten-Byte
	case 5:
		newTelegram->zeit.MINUTEN = byte;
		
		break;
		
	//	Sekunden-Byte
	case 6:
		newTelegram->zeit.SEKUNDEN = byte;
		
		break;
		
	case 7:
		newTelegram->zeit.RESERVIERT = byte;
		
		break;

	//	High-Byte der Millisekunden
	case 8:
		newTelegram->zeit.MILLISEKUNDEN = (WORD) (byte << 8); 
		
		break;
		
	//	Low-Byte der Millisekunden
	case 9:
		newTelegram->zeit.MILLISEKUNDEN |= (WORD) byte;
		
		break;
		
	//	Teilnehmer-Byte der Nutzdaten
	case 10:
		newTelegram->FM_Data.Teilnehmer.BYTE = byte;
		
		break;
		
	//	Funktions-Code der Nutzdaten
	case 11:
		newTelegram->FM_Data.FunktionsCode = byte;
		
		break;
		
		
	//	restliche Nutzdatenbytes
	default:
		newTelegram->FM_Data.NUTZDATEN.append(byte);
		
		break;
		
	}
}

void PollThread::start()
{
	run();
}

void PollThread::run()
{
	
}

PollThread::~PollThread()
{
	
}
class SendThread liest aus der gemeinsamen Liste der beiden Threads und sendet die Daten zu weiteren Verarbeitung weiter

Code: Alles auswählen

class SendThread : public QThread
{
	Q_OBJECT	
public:
	SendThread(QList<FmbData*> *usedTelegramList, QMutex *usedMutex);
	~SendThread();
	void start();
	
signals:
	void updateStatusTip(QString);
	void newData(FmbData*);
	void ping();
	
private slots:
	void readData();
	void sortData();
	unsigned long timeToMillisekunden(FmbData*);
	
private:
	QList<FmbData*>		*telegramList;
	FmbData		*telegram;
	QTimer		*sendTimer;
	QMutex		*mutex;

protected:
	void run();	
};


Code: Alles auswählen

SendThread::SendThread(QList<FmbData*> *usedTelegramList, QMutex *usedMutex)
{
	telegramList = usedTelegramList;
	mutex = usedMutex;
	sendTimer = new QTimer;
	sendTimer->setInterval(c_SEND_NEW_DATA_INTERVALL);
	sendTimer->start();
	connect(sendTimer, SIGNAL(timeout()), this, SLOT (readData()));
}

void SendThread::start()
{
	run();
}

void SendThread::run()
{
	
}

void SendThread::readData()
{
	mutex->lock();
	
	sortData();
	
	while(telegramList->isEmpty() == false)
	{
		emit newData(telegramList->first());
		delete telegramList->first();
		telegramList->removeFirst();
	}
	mutex->unlock();
}

void SendThread::sortData()
{
	bool getauscht;
	FmbData* tempTelegram;
	
	do
	{
		getauscht = false;
		for (int i_liste = 0; i_liste < (telegramList->count() - 1); i_liste++)
		{
			if (timeToMillisekunden(telegramList->at(i_liste)) > timeToMillisekunden(telegramList->at(i_liste + 1)))
			{
				tempTelegram = telegramList->at(i_liste);
				telegramList->removeAt(i_liste);
				telegramList->insert(i_liste + 1, tempTelegram);
				getauscht = true;
			}
		}
		
	}while (getauscht);
}
unsigned long SendThread::timeToMillisekunden(FmbData *telegram)
{
	return (unsigned long) telegram->zeit.MILLISEKUNDEN + telegram->zeit.SEKUNDEN * 1000 + telegram->zeit.MINUTEN * 1000 * 60 + telegram->zeit.MINUTEN * 1000 * 60 * 60;    
}


SendThread::~SendThread()
{
	
}
Also im Endeffekt gibt es zwei QLists, die das Problem verursachen könnten:

die interne " QList<unsigned char> receivedBytes " von PollThread und die " QList<FmbData*> *telegramList " von FmbSniffer, die zum Datenaustauch zwischen den beiden Threads genutzt wird.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Code: Alles auswählen

   while(telegramList->isEmpty() == false)
   {
      emit newData(telegramList->first());
      delete telegramList->first();
      telegramList->removeFirst();
   }
Du weist schon das das emit asynchron ausgeführt wird/werden kann wenn das Signal zu einem anderen Thread geht.

Ausserdem fehlt dort ein Lock, genauso wie bei der komischen Sortierfunktion --> http://doc.trolltech.com/4.3/qtalgorithms.html
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
bw1faeh0
Beiträge: 94
Registriert: 10. Oktober 2007 14:48
Wohnort: Braunschweig

Beitrag von bw1faeh0 »

Dass emit asynchron ausgeführt wird, stört mich nicht weiter. Ich muss nur sicher gehen, DASS es ausgeführt wird.

Ein Lock mittelst Mutex ist doch aber eingebaut, bevor ich sortiere und emite.
Die gesamte Methode void SendThread::readData() ist mittels eines Mutex gesichert.

Die komische Sortierfunktion musste ich nutzen, da die Elemente der Liste, die ich sortiere komplexe struct/union-konstrukte sind...
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

bw1faeh0 hat geschrieben:Dass emit asynchron ausgeführt wird, stört mich nicht weiter. Ich muss nur sicher gehen, DASS es ausgeführt wird.
Und was passiert dann in der nächsten Zeile? Habe das nicht umsonst geschrieben.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
bw1faeh0
Beiträge: 94
Registriert: 10. Oktober 2007 14:48
Wohnort: Braunschweig

Beitrag von bw1faeh0 »

Achso meinst du das... öhm...
ich hätte erwartet, dass er ne art Kopie erstellt, die er dann ermitet.

Wie kann ich denn dann sicher gehen, dass alle Daten emitet werden?
Antworten