View Full Version : [c#] threading e AccessViolationException
Ciao a tutti, sto facendo un progetto per l'università riguardante l'elaborazione video con opencl. per migliorare le performance vorrei usare vari thread in modo da poter scrivere su file i frames elaborati mentre un altro thread compie le elaborazioni sui frames successivi. per il momento ho creato solo il thread per andare a scrivere sul file mentre il resto è ancora tutto nella funzione principale.
Io ho un oggetto chiamato frameOut che contiene i dati elaborati riguardo a un frame e una funzione che dato frameOut aggiunge il frame al file. Il problema è che quando chiamo questa funzione nel nuovo thread mi da l'eccezione AccessViolationException. frameOut è dichiarato globalmente nella classe ma è inizializzato nella funzione principale (per inizializzarlo mi servono dei dati che ho solo dopo che ho eseguito alcune altre inizializzazioni). la cosa strana è che se invece in quel thread chiamo la funzione per mostrare il frame sul video (che prende lo stesso oggetto come input) non vengono lanciate eccezioni.
suggerimenti?
grazie a tutti
banryu79
16-07-2010, 11:42
Ciao a tutti, sto facendo un progetto per l'università riguardante l'elaborazione video con opencl. per migliorare le performance vorrei usare vari thread in modo da poter scrivere su file i frames elaborati mentre un altro thread compie le elaborazioni sui frames successivi. per il momento ho creato solo il thread per andare a scrivere sul file mentre il resto è ancora tutto nella funzione principale.
Io ho un oggetto chiamato frameOut che contiene i dati elaborati riguardo a un frame e una funzione che dato frameOut aggiunge il frame al file. Il problema è che quando chiamo questa funzione nel nuovo thread mi da l'eccezione AccessViolationException. frameOut è dichiarato globalmente nella classe ma è inizializzato nella funzione principale (per inizializzarlo mi servono dei dati che ho solo dopo che ho eseguito alcune altre inizializzazioni). la cosa strana è che se invece in quel thread chiamo la funzione per mostrare il frame sul video (che prende lo stesso oggetto come input) non vengono lanciate eccezioni.
suggerimenti?
grazie a tutti
Non conosco il thread model di C#, dato che lavoro in Java.
Comunque a naso direi che hai un data race su frameOut (magari solo su alcune sue parti interne) tra il thread che esegue I/O (lettore di frameOut) e il thread che elabora il frame successivo (scrittore di frameOut).
Potresti usare uno schema produttore-consumatore, con il thread scrittore che produce e infila in una coda bloccante oggetti frameOut man mano che processa i vari frame video, e con il thread lettore di frameOut che prende dalla coda bloccante gli oggetti frameOut e scrive su file.
Ho sparato grossolanamente: non avendo sottomano il codice è dificile capire se si possa sincronizzare in maniera più "fine" il tutto (anche perchè, ripeto, non conosco l'ambiente C#)
astorcas
16-07-2010, 11:55
prova a dare un occhio a questo (http://msdn.microsoft.com/en-us/library/bb300132.aspx):
ah mi ero dimenticato di dire che ho usato un blocco lock in tutti i casi in cui ci sono letture o scritture di frameOut. ora provo a dare un occhiata a quel link astorcas.
grazie
ah mi ero dimenticato di dire che ho usato un blocco lock in tutti i casi in cui ci sono letture o scritture di frameOut. ora provo a dare un occhiata a quel link astorcas.
grazie
ho provato la classe ReaderWriterLockSlim ma non è cambiato nulla. ho anche provato a inizializzare frameOut al momento della dichiarazione o nella funzione associata al thread (cosa in ogni caso non fattibile perchè a quel punto non ho i dati che mi servono e che ho fatto con dati arbitrari giusto per provare) ma cmq l'eccezione rimane :cry:
PS: mi da errore addirittura se dichiaro e inizializzo frameOut all'interno della funzione :confused:
banryu79
16-07-2010, 13:40
Non ti conviene postare un po' di codice?
A beneficio di chi mastica C#, naturalmente.
Comunque, nel tuo scenario, io (da inesperto, aggiungerei :D) non condividerei l'oggetto 'frameOut' tra i due thread sincronizzandone i suoi metodi di lettura/scrittura con i thread che si contendono frameOut di volta in volta ma farei come ti ho descritto sopra, con la coda bloccante.
astorcas
16-07-2010, 13:50
si infatti posta un po' di codice... così non saprei da dove cominciare :D, potrebbe essere che non chiudi gli stream una volta letto/scritto?
ok posto un po' di codice rilevante. non fate caso al fatto che non è molto elegante perchè si tratta solo di codice di prova. vi interesserà sapere che uso la libreria opencvsharp, un wrapper di opencv per c#.
class Main
{
private static CvWindow videoWindow;
private static IplImage frameOut;
private static AutoResetEvent outputEvt = new AutoResetEvent(false);
private static CvVideoWriter writer;
private static ReaderWriterLockSlim objLock = new ReaderWriterLockSlim();
private static void outputProc()
{
while (true)
{
outputEvt.WaitOne();
objLock.EnterWriteLock();
try
{
writer.WriteFrame(frameOut);
videoWindow.ShowImage(frameOut);
CvWindow.WaitKey(1);
}
finally
{
objLock.ExitWriteLock();
}
}
}
public static void main(Window1 win)
{
....
try
{
....
Thread outThread = new Thread(outputProc);
outThread.Start();
videoWindow = new CvWindow("output");
writer = new CvVideoWriter(fileFg, FourCC.DIVX, fps, new CvSize(width / 2, height / 2));
frameOut = new IplImage(width / 2, height / 2, BitDepth.U8, nChannels);
frameIn = capture.QueryFrame();
while(frameIn != null)
{
objLock.EnterWriteLock();
try
{
Marshal.Copy(rawSingleFrameOut, 0, frameOut.ImageData, sizeFrameOut); //copia dei dati dall'array all'immagine
}
finally
{
objLock.ExitWriteLock();
}
outputEvt.Set();
}
}
catch (Exception e)
{
....
}
}
}
ho troncato un bel po' di cose per non rendere tutto troppo complicato. se qualcosa non vi torna fatemi sapere. l'eccezione viene lanciata alla riga
writer.WriteFrame(frameOut);
nella funzione outputProc().
grazie
banryu79
16-07-2010, 15:13
Potrei sbagliare di brutto (ed è molto probabile) ma mi sembra che nel metodo main il tuo oggetto 'writer' viene inizializzato solo dopo la creazione e l'avvio del thread che esegue il metodo 'outputProc', dentro il quale, appunto, si invoca 'writer.WriteFrame'...
Può essere questo che causa la AccessViolationException?
Potrei sbagliare di brutto (ed è molto probabile) ma mi sembra che nel metodo main il tuo oggetto 'writer' viene inizializzato solo dopo la creazione e l'avvio del thread che esegue il metodo 'outputProc', dentro il quale, appunto, si invoca 'writer.WriteFrame'...
Può essere questo che causa la AccessViolationException?
in teoria lo scopo dell'AutoResetEvent è quello di andare avanti con l'esecuzione solo quando io chiamo il metodo set che come vedi avviene molto più in alto, inoltre non è un problema dell'oggetto writer perchè se io uso ad esempio il metodo toString non ci sono eccezioni. inoltre non è nemmeno un problema di frameOut per conto suo perchè quando chiamo la funzione showImage non mi da problemi. in qualche modo è un problema della funzione writeFrame in congiunzione con l'oggetto frameOut ma non capisco perchè :muro:
astorcas
16-07-2010, 17:59
ad occhio mi sembra che una volta che il primo .Set() è stato invocato il secondo thread avanza ma il primo non si ferma, non mi sembra thread-safe, o sbaglio? Forse dovresti usare più di un waitHandler? O magari un Mutex.
ad occhio mi sembra che una volta che il primo .Set() è stato invocato il secondo thread avanza ma il primo non si ferma, non mi sembra thread-safe, o sbaglio? Forse dovresti usare più di un waitHandler? O magari un Mutex.
mmm non saprei. in teoria il thread per l'output si dovrebbe fermare ogni volta quando chiamo il metodo waitOne fino a che nel thread principale non chiamo la set il che avviene dopo aver scritto nell'oggetto frameOut. in ogni caso farò qualche prova per vedere. inoltre ho il dubbio che non sia un problema solo di concorrenza perchè qualunque altro oggetto usato in quel modo non da errori, non vorrei che fosse un problema nella libreria e nelle sue classi e metodi
astorcas
16-07-2010, 19:33
mmm non saprei. in teoria il thread per l'output si dovrebbe fermare ogni volta quando chiamo il metodo waitOne fino a che nel thread principale non chiamo la set il che avviene dopo aver scritto nell'oggetto frameOut. in ogni caso farò qualche prova per vedere. inoltre ho il dubbio che non sia un problema solo di concorrenza perchè qualunque altro oggetto usato in quel modo non da errori, non vorrei che fosse un problema nella libreria e nelle sue classi e metodi
si il thread 2 si ferma su WaitOne aspettando che il thread 1 chiami Set, ma quando il thread 1 chiama Set, il thread 2 riprende, mentre il thread 1 continua la sua normale esecuzione. Spesso i due thread finiscono insieme nella loro regione critica. Io li sincronizzerei meglio.
per evitare che finiscano contemporaneamente nella regione critica uso la classe ReaderWriterLockSlim. forse non la uso nel modo corretto, beh domani vedrò di provare qualcosa. nel frattempo altri suggerimenti sono graditi :D
può sembrare assurdo ma il problema è legato al codec che seleziono al momento della chiamata del costruttore dell'oggetto writer. per alcuni di codec sulla console mi da questo messaggio:
Compiler did not align stack variables. Libavcodec has been miscompiled
and may be very slow or crash. This is not a bug in libavcodec,
but in the compiler. You may try recompiling using gcc >= 4.2.
Do not report crashes to FFmpeg developers.
[mpeg @ 0x8e7d1a0]invalid dts/pts combination
ed è in questi casi che ho il problema della accessviolationexception. il fatto è che i codec con cui non da problemi non sono utilizzabili nella realtà perchè non comprimo o comprimono pochissimo (anche più di 80MB per 15 s di video in 320x240 :eek: ) e quindi vorrei usare qualcosa tipo divx o xvid ma entrambi mi danno il suddetto problema. mi sono scaricato i codec xvid e li ho installati ma il problema rimane. inoltre se provo a far partire i programmi per la configurazione del decoder e dell'encoder ricevo questi i 2 seguenti errori rispettivamente:
"there was a problem starting xvid.ax"
e
"there was a problem starting xvidvfw.dll"
ho già provato a reinstallare ma non è servito è andato tutto come prima, ho anche riavviato ma niente :muro: . sembra che il mio pc abbia qualche problema con i codec eppure non ne ho mai installati che possano aver creato il casino perchè uso sempre vlc.
:help:
ho installato i codec divx. stesso problema nel mio programma :mc: (invece il programma di configurazione almeno parte)
banryu79
17-07-2010, 11:22
Ciao :)
Leggendo questo:
Compiler did not align stack variables. Libavcodec has been miscompiled
and may be very slow or crash. This is not a bug in libavcodec,
but in the compiler. You may try recompiling using gcc >= 4.2.
non è che, più che ai codec in se, si riferisce alla compilazione di Libavcodec?
Magari ti sta suggerendo di mettere le mani su una distribuzione compilata appunto con gcc versione 4.2 o superiore.
Oppure cambia libreria :D
Ciao :)
Leggendo questo:
non è che, più che ai codec in se, si riferisce alla compilazione di Libavcodec?
Magari ti sta suggerendo di mettere le mani su una distribuzione compilata appunto con gcc versione 4.2 o superiore.
Oppure cambia libreria :D
il problema c'entra in qualche modo con l'implementazione di ffmpeg già incluso dentro opencv. di opencv ho la versione 2.1 che a quanto mi risulta è già la versione più aggiornate.
per quanto riguarda il fatto di cambiare libreria, magari! ma non trovo altro che vada bene. questa ogni tanto mi salta fuori con sti stani problemi perchè la situazione è piuttosto incasinata: io chiamo direttamente le funzioni da opencvsharp (che è un wrapper di opencv per c#), questo poi si rivolge alle librerie di opencv che a sua volta usa ffmpeg. mi piacerebbe una libreria che si possa usare direttamente da c# e che faccia solo le 2 cose che mi servono (opencv invece fa un tot di cose che non mi interessante perchè me le implemento io direttamente in opencl per poter usare la gpu). e alla fine quello che mi serve è:
-poter prendere un frame alla volta da un video (e magari da una webcam) con i dati che mi vengono restituiti in forma grezza, un array di byte con i classici 3 byte per pixel
-poter scrivere in un file (o mostrare direttamente sullo schermo) il video dopo che l'ho elaborato e sempre in forma rgb
ma non ho trovato altre librerie abbastanza usabili che facessero tutto questo.
avete qualcosa da consigliare?
per rispondere a banryu il problema direi che c'entra sia con la libreria che con i codec. quando chiamo il costruttore per l'oggetto writer tra i parametri gli passo un codice per dirgli quale codec usare. li ho provati tutti con i seguenti risultati:
- alcuni codec non vengono trovati e fallisce il costruttore (normale)
- alcuni codec funzionano ma non comprimono un cavolo
- infine altri codec mi danno quel messaggio e poi l'eccezione (tra cui xvid e divx)
per i consigli riguardo ad un altra libreria mi è sembrato più appropriato aprire un altro thread apposito, anche perchè così magari un'altra persona in cerca di una simile libreria la trova più facilmente il thread è questo:
http://www.hwupgrade.it/forum/showthread.php?p=32633177
tornando in topic ho fatto un po' di prove e ho messo un contatore di quante volte viene lanciata l'eccezione. selezionando alcuni codec succede per tutti i frames con altri circa il 72% delle volte. tutto ciò non mi dice nulla. non so a voi :confused:
ho trovato nel sito di opencvsharp qualcuno che aveva lo stesso problema e che sosteneva dipendesse dal fatto che aveva usato una dll sbagliata (non specificava meglio) cmq mi sono riscaricato e ricompilato tutto e ora ho un altro problema. cioè sempre la stessa eccezione ma in un altro punto. è nella funzione principale e si verifica anche se elimino l'altro thread (per cui non c'entra nulla con la concorrenza) sono sempre più convinto che quelle libreria (anzi quella che ci sta sotto cioè opencv) sia un cesso. qua è la trovo altri che nominano il problema ma senza alcuna soluzione :mc:
mi sono fatto un progetto nuovo e vuoto e chiamando la stessa funzione ho lo stesso problema. ho provato anche a tornare alla precedente versione della libreria ma niente da fare. deve essere cambiato qualcosa nel sw del mio pc, a questo punto non trovo altra spiegazione. magari qualcosa che non va in visual studio 2010. ma non so proprio come risolvere :muro:
ho fatto altre prove. a quanto pare in un progetto "console application" funziona normalmente mentre non va se creo una "wpf application" (che è quello che stavo facendo io). il fatto è che l'interfaccia grafica mi serve. :help:
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.