Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

stringstream + threads

18 réponses
Avatar
Mickybadia
Bonjour les amis,

J'ai un stringstream défini globalament, et ensuite un programme
double-thread, l'un (W) qui écrit dedans et l'autre (R) qui lit. En
gros, W tourne en boucle et filtre std::in pour R, le thread principal
(qui a créé W) et qui lit l'entrée filtrée dans le stringstream.

...et ça ne marche pas : W écrit bien dans le stream mais les getline
dans R ne retournent que des lignes vides. Une explication?

Merci.




Résumé du code pertinent :

#include <sstream>
static std::stringstream fcin; // Filtered cin

class IOThread : public QThread {
public:
void run() { // définit W
string ln;
while (getline(cin, ln)) {
if (filter(ln))
fcin << ln << endl;
}
cout << "Reached end of input, IO exits." << endl;
}
};

class IO { //thread créé et W lancé dans le constructeur
public:
string readln() {
string line;
getline(fcin, line);
trace("(input) " + line);
return line;
}
}

// puis dans le code, un objet IO créé

--
Micky

8 réponses

1 2
Avatar
Fabien LE LEZ
On Wed, 15 Jul 2009 18:24:07 -0400, Mickybadia
:

if (filter(ln)) {
fcinAccess.lock();
fcin.push_back(ln);
cerr << "PUSHED a line in fcin queue (now size "
<< fcin.size() << "): " << ln << endl;
fcinAccess.unlock();
}



Ça ne répond pas directement à ta question, mais tu as un problème
potentiel ici. Que se passe-t-il si "push_back" ou "cerr << ..." lance
une exception ? "unlock()" n'est jamais appelée !

La solution habituelle ici s'appelle RAII (cf Google pour plus
d'infos) :

class MutexLocker // Est-ce que ça n'existe pas déjà dans Qt ?
{
public:
MutexLocker (QMutex& m) : le_mutex (m) { le_mutex.lock(); }
~MutexLocker() { le_mutex.unlock(); }
private:
QMutex le_mutex;
};


if (filter(ln))
{
MutexLocker locker (fcinAccess);
fcin.push_back(ln);
cerr << "PUSHED a line in fcin queue (now size "
<< fcin.size() << "): " << ln << endl;
}// Ici, destruction de "locker",
// c'est-à-dire libération de fcinAccess.
Avatar
Michael Doubez
On 16 juil, 20:31, Fabien LE LEZ wrote:
On Wed, 15 Jul 2009 18:24:07 -0400, Mickybadia
:

>       if (filter(ln)) {
>         fcinAccess.lock();
>           fcin.push_back(ln);
>           cerr << "PUSHED a line in fcin queue (now size "
>                << fcin.size() << "): " << ln << endl;
>         fcinAccess.unlock();
>       }

Ça ne répond pas directement à ta question, mais tu as un problèm e
potentiel ici. Que se passe-t-il si "push_back" ou "cerr << ..." lance
une exception ? "unlock()" n'est jamais appelée !



Juste une question en l'air: je me demande si il y a vraiment une
chance que cerr lance une exception ( sauf si exception() est
positionné).

Il n'y a pas de garantie nothrow et je suppose qu'un streambuf peut
lancer une exception mais en pratique je m'attendrais plutôt à ce que
la stream se positionne le bit correspondant.

En regardant le standard, il y a §27.6.2.1/3 (§27.7.2.1/3 dans n2914):
If one of these called functions throws an exception, then unless
explicitly noted otherwise the output function sets badbit in error
state. If badbit is on in exceptions(), the output function rethrows
the exception without completing its actions, otherwise it does not
throw anything and treat as an error.

Est ce à dire que les fonctions de ostream attrapent toutes les
exceptions venant de rdbuf ?

La solution habituelle ici s'appelle RAII       (cf Google pour plu s
d'infos) :

class MutexLocker // Est-ce que ça n'existe pas déjà dans Qt ?


[snip]

Si. On peux le voir dans le code qu'a posté James Kanze, ça s'appelle
QMutexLocker.

--
Michael
Avatar
James Kanze
On Jul 16, 8:31 pm, Fabien LE LEZ wrote:
On Wed, 15 Jul 2009 18:24:07 -0400, Mickybadia
:



> if (filter(ln)) {
> fcinAccess.lock();
> fcin.push_back(ln);
> cerr << "PUSHED a line in fcin queue (now size "
> << fcin.size() << "): " << ln << endl;
> fcinAccess.unlock();
> }



Ça ne répond pas directement à ta question, mais tu as un
problème potentiel ici. Que se passe-t-il si "push_back" ou
"cerr << ..." lance une exception ? "unlock()" n'est jamais
appelée !



La solution habituelle ici s'appelle RAII



Il utilise QThreads. La solution s'appelle QMutexLocker.

(cf Google pour plus d'infos) :



class MutexLocker // Est-ce que ça n'existe pas déjà dans Qt ?



Oui, mais dans une form qui fonctionne:-).

{
public:
MutexLocker (QMutex& m) : le_mutex (m) { le_mutex.lock(); }
~MutexLocker() { le_mutex.unlock(); }
private:
QMutex le_mutex;



Tu n'as pas oublié une '&' quelque part ? Ça m'étonnerait que
QMutex support la copie.

};



--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
Fabien LE LEZ
On Fri, 17 Jul 2009 00:37:14 -0700 (PDT), James Kanze
:

Tu n'as pas oublié une '&' quelque part ?



Oups, oui, désolé.

C'était pour voir si tu suivais :-p
Avatar
James Kanze
On Jul 17, 8:37 am, Michael Doubez wrote:
On 16 juil, 20:31, Fabien LE LEZ wrote:



> On Wed, 15 Jul 2009 18:24:07 -0400, Mickybadia
> :



> > if (filter(ln)) {
> > fcinAccess.lock();
> > fcin.push_back(ln);
> > cerr << "PUSHED a line in fcin queue (now size "
> > << fcin.size() << "): " << ln << endl;
> > fcinAccess.unlock();
> > }



> Ça ne répond pas directement à ta question, mais tu as un
> problème potentiel ici. Que se passe-t-il si "push_back" ou
> "cerr << ..." lance une exception ? "unlock()" n'est jamais
> appelée !



Juste une question en l'air: je me demande si il y a vraiment
une chance que cerr lance une exception ( sauf si exception()
est positionné).



Il n'y a pas de garantie nothrow et je suppose qu'un streambuf
peut lancer une exception mais en pratique je m'attendrais
plutôt à ce que la stream se positionne le bit correspondant.



En effet.

En regardant le standard, il y a §27.6.2.1/3 (§27.7.2.1/3 dans n2914) :
If one of these called functions throws an exception, then unless
explicitly noted otherwise the output function sets badbit in error
state. If badbit is on in exceptions(), the output function rethrows
the exception without completing its actions, otherwise it does not
throw anything and treat as an error.



Est ce à dire que les fonctions de ostream attrapent toutes les
exceptions venant de rdbuf ?



Oui. Mais formellement, la fonction (ici, operator<<) peut
lever n'importe quelle exception pour n'importe quelle raison,
pourvu que l'implémentation le documente.

> La solution habituelle ici s'appelle RAII (cf Google pour
> plus d'infos) :



> class MutexLocker // Est-ce que ça n'existe pas déjà dans Qt ?



[snip]



Si. On peux le voir dans le code qu'a posté James Kanze, ça
s'appelle QMutexLocker.



Chose que le poster initial aurait dû déjà savoir, puisque c'est
très bien documenté chez QT. (Je ne connais pas QT, et il m'a
fallu moins de dix minutes pour trouver toutes les informations
dont j'avais besoin pour mon exemple.)

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
Fabien LE LEZ
On Fri, 17 Jul 2009 00:44:07 -0700 (PDT), James Kanze
:

Chose que le poster initial aurait dû déjà savoir



Je suppose qu'il n'avait pas compris l'importance de RAII.
Avatar
Mickybadia
OK merci à tous pour votre implication dans le groupe.

QMutexlocker je connais, while true c'est pas terrible et un static
c'est moins joli qu'une classe je le sais parfaitement, mais ma question
portait sur l'accès à 'fcin' et j'ai réduit mon code en évitant le
non-standard moins lisible.

Vos remarques sont éviemment utiles à tout le monde qui les lit, mais je
reste étonné du comportement du code que j'ai posté car le lecteur ne
lisait qu'une taille de deque nulle (ou un stringbuf vide dans la
première version) alors que bien modifié par l'écrivain, ce que je
n'explique toujours pas.

[fu2 thread "extern"]
Avatar
James Kanze
On Jul 18, 2:11 pm, Mickybadia wrote:

Vos remarques sont éviemment utiles à tout le monde qui les
lit, mais je reste étonné du comportement du code que j'ai
posté car le lecteur ne lisait qu'une taille de deque nulle
(ou un stringbuf vide dans la première version) alors que bien
modifié par l'écrivain, ce que je n'explique toujours pas.



Il y a bien deux choses qui posent des problèmes dans la
première version : d'abord, les « erreurs » dans les iostream
sont « sticky », c-à-d qu'elles persistent jusqu'on les remette
à zéro, et deuxièmement, il n'y a aucune garantie que tu puisses
accéder à un flux depuis deux threads différents sans une
synchronisation externe. La première fait que même avec une
synchronisation adequate (disons mon code de MessageQueue, mais
avec un stringstream à la place d'une deque), il faudrait
remettre les erreurs à zéro (ios::clear()) avant chaque essai.
(Un état d'erreur fait que toute fonction sauf clear est un
no-op. Donc, une fois que tu as lu dans le flux vide, tu ne peux
même plus y écrire.)

Dans l'ensemble, je crois que stringstream est assez mal adapté
pour ce que tu veux. En plus des problèmes déjà cités, il ne
libère pas la mémoire déjà lu (puisqu'il supporte seek), ce qui
fait qu'à la longue, dans ton utilisation, il va utiliser de
plus en plus de mémoire. Jusqu'à ce qu'il n'y en ait plus.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
1 2