Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 19
  1. #1

    [C++] init di una classe all'interno di un thread

    Salve,

    ho scritto una piccola classe per gestire le funzioni waveIn della waveForm API di windows. La classe è composta da questi due files:

    waveCapture.h
    waveCapture.cpp

    mentre la classe funziona benissimo all'interno di main() ho un problema ad usarla dentro ad un thread (l'inizializzazione va a buon termine ma chiamando il metodo principale mi torna un unhanlde exception: Access violation writing location)

    ecco il codice del programma thread:

    codice:
    #include <stdio.h>
    #include <stdlib.h>
    #include "waveCapture.h"
    
    DWORD WINAPI startRecorder(const LPVOID lpParam);
    DWORD WINAPI stopRecorder(void);
    
    bool stopThreadFlag = false;
    
    struct parametri
    {
    	WORD uDevice;
    	DWORD nSamplesPerSec;
    	WORD wBitsPerSample;
    	WORD nChannels;
    	const char* szFilePath;
    };
    
    int main()
    {
    	parametri *p      = new (parametri);
    	p->uDevice        = 0;
    	p->nSamplesPerSec = 44100;
    	p->wBitsPerSample = 16;
    	p->nChannels      = WAVE_STEREO;
    	p->szFilePath     = "C:\\Users\\giangaetano\\Desktop\\mmio\\waveCapture.WAVE";
    
    	HANDLE hthread[2];
    	DWORD dwID[2];
    
    	// Launch Capturing Thread: thread[0]
    	hthread[0] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&startRecorder,p,0,&dwID[0]);
    
    	printf("Started capturing...(press any key to stop)\n\n");
    	system("pause");
    
    	// Once any key is pressed, stop thread[0] by launching thread[1]
    	hthread[1] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&stopRecorder,NULL,0,&dwID[1]);
    	CloseHandle(hthread[1]);
    	CloseHandle(hthread[0]);
    
    	printf("\nStopped capturing!\n\n");
    
    	system("pause");
    	delete p;
    	return EXIT_SUCCESS;
    }
    
    DWORD WINAPI startRecorder(const LPVOID lpParam)
    {
    	// Get the params
    	parametri p;
    	p = *((parametri*)lpParam);
    
    	// Init waveCapture class
    	waveCapture pwc;
    	printf("%s, %d, %d, %d\n",
    		waveCapture::szVersion,
    		pwc.__dwSamplePerSec(),
    		pwc.__wBitsPerSample(),
    		pwc.__nChannels()
    		);
    
    	// Start capturing
    	pwc.start();
    
    	// Stop capturing:
    	pwc.stop();
    
    	return 0;
    }
    
    DWORD WINAPI stopRecorder(void)
    {
    	stopThreadFlag = true;
    	return 0;
    }
    C'è qualche accorgimento speciale che devo seguire se sviluppo una classe che potrebbe essere usata da dentro un thread?

    grazie
    Alla batteria dai retta ballA

  2. #2
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Un'infinità, ma nel tuo caso potrebbe bastare mettere una WaitForSingleObjects per thread (o una WaitForMultipleObjects) qui:
    codice:
    	hthread[1] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&stopRecorder,NULL,0,&dwID[1]);
    
           WaitForMultipleObjects(2,htread); 
    
    	CloseHandle(hthread[1]);
    	CloseHandle(hthread[0]);
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  3. #3
    non ci avevo pensato:

    codice:
    WaitForMultipleObjects(2, hthread, true, INFINITE);
    può far benissimo in quella parte del codice, ma tuttavia non risolve il problema :-(
    Alla batteria dai retta ballA

  4. #4
    l'inizializzazione avviene correttamente, se non chiamassi start() non ci sarebbe errore...non so proprio cosa possa essere, ecco il codice di start() nella classe:

    codice:
    // Define: start() (fake)
    bool waveCapture::start()
    {
    	DWORD dwCBufferLength = getSuggestedBufferSize();
    	if(this->_start(0, dwCBufferLength, dwCNumBuffers))
    		return true;
    	else
    		return false;
    }
    
    // Define: start(WORD) (fake)
    bool waveCapture::start(const WORD uDevice)
    {
    	DWORD dwCBufferLength = getSuggestedBufferSize();
    	if(this->_start(uDevice, dwCBufferLength, dwCNumBuffers))
    		return true;
    	else
    		return false;
    }
    
    // Define: start(WORD, DWORD, DWORD) (fake)
    bool waveCapture::start(const WORD uDevice, const DWORD dwBufferLength, const DWORD dwNumBuffers)
    {
    	if(this->_start(uDevice, dwBufferLength, dwNumBuffers))
    		return true;
    	else
    		return false;
    }
    
    // Define: _start(WORD, DWORD, DWORD) (real)
    bool waveCapture::_start(const WORD uDevice, const DWORD dwBufferLength, const DWORD dwNumBuffers)
    {
    	// need dwNumBuffers in stop() as well,
    	// so I set __dwNumBuffers under the counter
    	__dwNumBuffers = dwNumBuffers;
    
    	// Define WAVEFORMATEX Structure (WAVEFORMATEX wf):
    	wf.wFormatTag      = WAVE_FORMAT_PCM;
    	wf.wBitsPerSample  = _wBitsPerSample;
    	wf.nChannels       = _nChannels;
    	wf.nSamplesPerSec  = _dwSamplePerSec;
    	wf.nBlockAlign     = (wf.nChannels * wf.wBitsPerSample) / 8;
    	wf.nAvgBytesPerSec = (wf.nSamplesPerSec * wf.nBlockAlign);
    	wf.cbSize          = 0;
    
    	// Create event:
    	hevent = CreateEvent(NULL,FALSE,FALSE,NULL);
    
    	// WaveInOpen
    	if(waveInOpen(&hwi,uDevice,(LPWAVEFORMATEX)&wf,(DWORD)hevent,0,CALLBACK_EVENT) != MMSYSERR_NOERROR)
    	{
    		return false;
    	}
    
    	// Define WAVEHDR Structure:
    	buff = new WAVEHDR[dwNumBuffers];
    	for (int i = 0; i<(int)dwNumBuffers; i++)
    	{
    		ZeroMemory(&buff[i], sizeof(buff[i]));
    		buff[i].lpData          = (char*) malloc(dwBufferLength);
    		buff[i].dwBufferLength  = dwBufferLength;
    		buff[i].dwBytesRecorded = 0;
    		buff[i].dwUser          = 0;
    		buff[i].dwFlags         = 0;
    		buff[i].dwLoops         = 0;
    
    		if(waveInPrepareHeader(hwi, &buff[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
    		{
    			return false;
    		}
    
    		if(waveInAddBuffer(hwi, &buff[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
    		{
    			return false;
    		}
    	}
    
    	// Start capturing...
    	if(waveInStart(hwi) != MMSYSERR_NOERROR)
    	{
    		printf("waveInStart: ERROR!\n");
    		return false;
    	}
    
    	_dwBufferCount      = 0;
    	dwTotalBufferLength = 0;
    	return true;
    }
    Alla batteria dai retta ballA

  5. #5
    una domanda, ma devo sempre e cmq cancellare il puntatore alla class anche quando essa è chiamata dentro un thread?

    non capisco come ma ora il codice seguente funziona alla perfezione! (ma se cancello il puntatore prima di ritornare alla main mi da unhandle exception!!)

    codice:
    #include <stdio.h>
    #include <stdlib.h>
    #include "waveCapture.h"
    
    DWORD WINAPI startRecorder(const LPVOID lpParam);
    DWORD WINAPI stopRecorder(void);
    
    bool stopThreadFlag = false;
    
    struct parametri
    {
    	WORD uDevice;
    	DWORD nSamplesPerSec;
    	WORD wBitsPerSample;
    	WORD nChannels;
    	const char* szFilePath;
    };
    
    int main()
    {
    	HANDLE hthread[2];
    	DWORD dwID[2];
    	
    	parametri *p      = new (parametri);
    	p->uDevice        = 1;
    	p->nSamplesPerSec = 44100;
    	p->wBitsPerSample = 16;
    	p->nChannels      = WAVE_STEREO;
    	p->szFilePath     = "C:\\Users\\giangaetano\\Desktop\\mmio\\waveCapture.WAVE";
    
    	// Launch Capturing Thread: thread[0]
    	hthread[0] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&startRecorder,p,0,&dwID[0]);
    
    	printf("Started capturing...(press any key to stop)\n\n");
    	system("pause");
    
    	// Once any key is pressed, stop thread[0] by launching thread[1]
    	hthread[1] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&stopRecorder,NULL,0,&dwID[1]);
    
    	WaitForMultipleObjects(2, hthread, true, INFINITE);
    
    	CloseHandle(hthread[1]);
    	CloseHandle(hthread[0]);
    
    	printf("\nStopped capturing!\n\n");
    
    	system("pause");
    	return EXIT_SUCCESS;
    }
    
    DWORD WINAPI startRecorder(const LPVOID lpParam)
    {
    
    	// Get the params
    	parametri p;
    	p = *((parametri*)lpParam);
    
    	// Init waveCapture class
    	waveCapture *pwc = new waveCapture(p.nSamplesPerSec, p.wBitsPerSample, p.nChannels);
    	printf("%s, %d, %d, %d\n",
    		waveCapture::szVersion,
    		pwc->__dwSamplePerSec(),
    		pwc->__wBitsPerSample(),
    		pwc->__nChannels()
    		);
    
    	// Start capturing
    	pwc->start(p.uDevice);
    
    	// Create an empty WAVE File
    	pwc->createWAVEFile(p.szFilePath);
    
    	// Get the suggested buffer size (bytes)
    	DWORD bufflen = pwc->getSuggestedBufferSize();
    
    	// Alloc buffer
    	char* pWAVBuffer = new char[bufflen];
    
    	// Loop
    	while(1)
    	{
    		if(!stopThreadFlag)
    		{
    			// Read WAVE Chunk
    			DWORD dwBytesRec = pwc->readBuffer(pWAVBuffer);
    
    			// Save WAVE Chunk
    			pwc->saveWAVEChunk(pWAVBuffer);
    
    		} else {
    			break;
    		}
    	}
    
    	// Stop Capturing
    	pwc->stop();
    
    	// Add the RIFF header to the WAVE File and close it
    	pwc->closeWAVEFile();
    
    	// Delete the buffer:
    	delete pWAVBuffer;
    
    	// Free memory
    	//delete pwc;
    
    	return 0;
    }
    
    DWORD WINAPI stopRecorder(void)
    {
    	stopThreadFlag = true;
    	return 0;
    }
    mah!
    Alla batteria dai retta ballA

  6. #6
    forse era VC++ impazzito, ora va tutto bene!!!

    http://theartofweb.net/cpp/waveCapture_Thread.txt
    Alla batteria dai retta ballA

  7. #7
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Spiacente, ma ci credo poco. Il codice (se non l'hai modificato nel frattempo trovando l'inghippo) NON funziona. E l'errore non è dovuto al multithreading (come pensavo in un primo momento.) ma ad un uso errato delle funzioni e delle allocazioni di memoria.
    Eseguendo il codice in singlethreading ottengo comunque un errore di accesso alla memoria e il problema sono due righe:

    in waveCapture.h
    WAVEHDR* buff;

    nella funzione _start
    buff = new WAVEHDR*[dwNumBuffers];

    Non puoi allocare un array dinamico in quel modo.

    Con WAVEHDR* buff; prepari il puntatore per una singola WAVEHDR
    Per allocare un array devi usare un doppio puntatore.
    codice:
    WAVEHDR** buff;
    buff = new WAVEHDR*[dwNumBuffers];
    e poi inizializzare ogni singolo campo:
    codice:
    buff[i] = new WAVEHDR;
    (ovviamente dovrai accedere ai campi con
    buff[i]->
    etc.

    Poi c'è un errore più fine. Quando il distruttore distrugge buff, la registrazione è ancora in corso e questo corrompe ulteriormente la memoria ( se tu avessi deallocato anche buff[i].lpdata te ne saresti accorto subito).
    La documentazione di waveInPrepareHeader infatti dice:
    You must call this function before freeing the buffer. After passing a buffer to the device driver with the waveInAddBuffer function, you must wait until the driver is finished with the buffer before calling waveInUnprepareHeader. Unpreparing a buffer that has not been prepared has no effect, and the function returns zero.
    Io modificherei il codice come segue per evitare problemi in futuro:
    in waveCapture.h
    WAVEHDR** buff;

    in waveCapture.cpp
    codice:
      // in _start
    	// Define WAVEHDR Structure:
    	buff = new WAVEHDR*[dwNumBuffers];
    	for (int i = 0; i<(int)dwNumBuffers; i++)
    	{
    		buff[i] = new WAVEHDR;
    		ZeroMemory(buff[i],sizeof(WAVEHDR));
    
    // in _stop
    
    	MMRESULT h;  
    	for (int u = 0; u<(int)__dwNumBuffers; u++)
    	{
    		do {
    
    			h = waveInUnprepareHeader(hwi, buff[u], sizeof(WAVEHDR));
    			switch (h) {
    				case MMSYSERR_INVALHANDLE:
    					printf("invalid handle\n");
    					break;
    				case MMSYSERR_NODRIVER:
    					printf("no driver\n");
    					break;
    				case MMSYSERR_NOMEM:
    					printf("no mem\n");
    					break;
    				case WAVERR_STILLPLAYING:
    					printf("still playing\n");
    					break;
    				case MMSYSERR_NOERROR:
    					printf("ok\n");
    					break;
    			}
    		} while (h != MMSYSERR_NOERROR); 
    	}
    
    // nel distruttore
    
    	for (int u = 0; u<(int)__dwNumBuffers; u++)
    	{
    		free( buff[u]->lpData ); // visto allochi con malloc.
    	}
    	delete[] buff;
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  8. #8
    sono esterefatto per come hai risolto il problema e per il tuo interessamento...in effetti mi ero lasciato ingannare dall'apparente funzionamento in singlethreading e non sapevo più dove sbattere la testa...e sopratutto continuavo ad usare in modo errato la WAVDHR, per non parlare poi della deallocazione etc...

    devo veder ancora passare molta acqua sotto ai mulini prima che diventi un bravo programmatore

    grazie ancora
    Alla batteria dai retta ballA

  9. #9
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    C'è ancora un altro grosso problema di cui non te ne accorgi in singlethreading o con un unico thread (ne devi avere almeno due concorrenti) e riguarda la funzione _start e il distruttore.
    E' un errore molto subdolo e per risolverlo occorrerebbe riprogettare tutta la classe.
    Per il momento, quindi, ti consiglio di lasciar perdere il multithreading e concentrarti sul linguaggio in se.

    In ogni caso evita la CreateThread in C/C++ e usa invece _beginthreadex.
    http://forum.html.it/forum/showthrea...4#post12792064
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  10. #10
    per multithreading intendi un thread che usa la classe e altri che fanno altre cose? perchè non si può cmq avere più di un azione di capturing nello stesso momento...
    Alla batteria dai retta ballA

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2026 vBulletin Solutions, Inc. All rights reserved.