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

std::cout et multi-thread

8 réponses
Avatar
Philip K. Dick
Hello

J'ai un programme C++ multi-threadé qui contient plein
de std::cout << "bla bla" << xxx << "bla bla bla" << xxx << std::endl;
(idem avec cerr)

Les traces se mélangent souvent, aussi je cherche un moyen de les
traiter dans un seul thread, tout en minimisant les modifications
du code (par exemple avec une classe xxx exportant une méthode cout/cerr)

Est-ce que cela existe déjà ?

Merci,

PKD

8 réponses

Avatar
Alain Migeon
In article <f04vs7$5jf$,
says...
Hello

J'ai un programme C++ multi-threadé qui contient plein
de std::cout << "bla bla" << xxx << "bla bla bla" << xxx << std::endl;
(idem avec cerr)

Les traces se mélangent souvent, aussi je cherche un moyen de les
traiter dans un seul thread, tout en minimisant les modifications
du code (par exemple avec une classe xxx exportant une méthode cout/cer r)

Est-ce que cela existe déjà ?

Merci,

PKD


Tu peux créer une queue dans laquelle tu places les chaînes à imprime r.

Mais il faudra implémenter un système de signal à la thread qui va
imprimer, ainsi que protéger l'accès à la queue.

Sinon, il est possible d'utiliser un sémaphore que l'on prend avant le
cout et qu'on libère juste après.

_________________________________________________
Alain Migeon
Please reverse alain and migeon for replying.

Avatar
adebaene
On Apr 18, 1:36 pm, "Philip K. Dick" wrote:
Hello

J'ai un programme C++ multi-threadé qui contient plein
de std::cout << "bla bla" << xxx << "bla bla bla" << xxx << std::endl;
(idem avec cerr)

Les traces se mélangent souvent, aussi je cherche un moyen de les
traiter dans un seul thread, tout en minimisant les modifications
du code (par exemple avec une classe xxx exportant une méthode cout/cer r)

Est-ce que cela existe déjà ?


En utilisant des temporaires:

class SyncCout
{
static Lock m_lock; //spécifique à ta plate-forme
public:
SyncCout()
{
m_lock.lock();
}

~SyncCout()
{
m_lock.unlock();
}
};
Lock SyncCout::m_lock;

template<typename T> inline SyncCout const& operator<<(SyncCout const&
dest, T const& obj)
{
std::cout<<obj;
return dest ;
}

inline SyncCout const& operator<<(SyncCout const& dest, std::ios_base&
(*manip)( std::ios_base& ) )
{
std::cout<<manip;
return dest ;
}

inline SyncCout const& operator<<(SyncCout const& dest, std::ostream&
(*manip)( std::ostream& ) )
{
std::cout << manip ;
return dest ;
}

Ensuite, tu remplaces partout dans ton code "std::cout<<blabla....."
par "SyncCout()<<blabla..."

Arnaud

Avatar
HERMITTE Luc
On 18 avr, 13:36, "Philip K. Dick" wrote:
Hello

J'ai un programme C++ multi-threadé qui contient plein
de std::cout << "bla bla" << xxx << "bla bla bla" << xxx << std::endl;
(idem avec cerr)

Les traces se mélangent souvent, aussi je cherche un moyen de les
traiter dans un seul thread, tout en minimisant les modifications
du code (par exemple avec une classe xxx exportant une méthode cout/cer r)

Est-ce que cela existe déjà ?


Il doit bien y avoir un moyen de définir son propre streambuf qui
encapsulera d'autres streambufs (un par thread ; voir à utiliser des
TSS), non?
Après, il reste à synchroniser les flush, et à détourner le streamb uf
de std::cout pour y mettre le notre.

Pour ce qui est des synchronisations avec cin, je soupçonne que cela
sera moins facile.


Sinon, il existe des systèmes de log qui se posent la question de
pouvoir fonctionner en environnement MT.

--
Luc Hermitte

Avatar
James Kanze
On Apr 18, 1:36 pm, "Philip K. Dick" wrote:

J'ai un programme C++ multi-threadé qui contient plein
de std::cout << "bla bla" << xxx << "bla bla bla" << xxx << std::endl;
(idem avec cerr)

Les traces se mélangent souvent, aussi je cherche un moyen de les
traiter dans un seul thread, tout en minimisant les modifications
du code (par exemple avec une classe xxx exportant une méthode cout/cer r)

Est-ce que cela existe déjà ?


J'utilise normalement un wrapper du flux de sortie ; il
s'occupe non seulement du lock, mais aussi de générer les têtes
de lignes, assurer un flush à la fin, etc. Grosso modo :

class OutputStreamWrapper
{
public:
OutputStreamWrapper( std::ostream* dest )
: myCounter( new int() )
, myStream( dest )
{
++ (*myCounter) ;
if ( dest != NULL ) {
pthread_mutex_lock( logMutext ) ;
}
}
OutputStreamWrapper( OutputStreamWrapper const& other )
: myCounter( other.myCounter )
, myStream( other.myStream )
{
++ (*myCounter) ;
}
~OutputStreamWrapper()
{
-- (*myCounter) ;
if ( *myCounter == 0 ) {
if ( myStream != NULL ) {
myStream->flush() ;
}
delete myCounter ;
pthread_mutex_unlock( logMutext ) ;
}
}
std::ostream* stream() const
{
return myStream ;
}

private:
int* myCounter ;
std::ostream* myStream ;
} ;

template< typename T >
OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest, T const& obj )
{
std::ostream* s = dest.stream() ;
if ( s != NULL ) {
*s << obj ;
}
return dest ;
}

template< typename T >
inline OutputStreamWrapper const&
operator<<(
OutputStreamWrapper const&
dest,
T const& obj )
{
std::ostream* stream = dest.stream() ;
if ( stream != NULL ) {
*stream << obj ;
}
return dest ;
}

// Je ne me rappelle plus pourquoi il a fallu celle-ci...
inline OutputStreamWrapper const&
operator<<(
OutputStreamWrapper const&
dest,
char const* cString )
{
std::ostream* stream = dest.stream() ;
if ( stream != NULL ) {
*stream << cString ;
}
return dest ;
}

// Parce que les manipulateurs sont aussi des templates...
inline OutputStreamWrapper const&
operator<<(
OutputStreamWrapper const&
dest,
std::ios_base& (* manip)( std::ios_base& ) )
{
std::ostream* stream = dest.stream() ;
if ( stream != NULL ) {
*stream << manip ;
}
return dest ;
}

// Parce que les manipulateurs sont aussi des templates...
inline OutputStreamWrapper const&
operator<<(
OutputStreamWrapper const&
dest,
std::ostream& (* manip)( std::ostream& ) )
{
std::ostream* stream = dest.stream() ;
if ( stream != NULL ) {
*stream << manip ;
}
return dest ;
}

J'utilise à peu près le même, mais avec quelque features en
plus. (Chez moi, c'est une fonctionne qui le crée, en fonction
des paramètres de configuration ; et à la place de std::cout,
j'utilise un flux avec un streambuf sur mesure qui est informé
du début de chaque trace, et modifie ses têtes de lignes en
conséquence.)

--
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
espie
Je n'ai pas eu trop a faire ca, mais j'avoue que j'aurais effectivement
tendance a rajouter un streambuf, et a juste proteger les entrees-sorties
effectives sur le flux par un lock, histoire de minimiser la section
non parallelisable. Evidemment, ca va dependre de la densite d'entrees-sorties
et du niveau de concurrence requis...
Avatar
James Kanze
On Apr 19, 10:47 am, (Marc Espie) wrote:
Je n'ai pas eu trop a faire ca, mais j'avoue que j'aurais
effectivement tendance a rajouter un streambuf, et a juste
proteger les entrees-sorties effectives sur le flux par un
lock, histoire de minimiser la section non parallelisable.
Evidemment, ca va dependre de la densite d'entrees-sorties et
du niveau de concurrence requis...


Il y a en effet une autre solution : utiliser un streambuf per
thread, avec toutes les données gardées en buffer jusqu'au flush
de la fin du message de log, puis synchroniser, et écrire vers
le flux final (voire y écrire d'une écriture atomique
directement). Reste que dans les logs un peu plus compliquées,
il faut bien signaler la fin d'un message d'une façon ou une
autre. Dans beaucoup de cas, évidemment, reconnaître un 'n'
et écrire chaque ligne de façon atomique fera l'affaire.

Mais ça suppose aussi la possibilité de rétrouver le flux (ou le
buffer) rapidement en fonction du thread. Ce qui n'est pas
toujours donné non 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

Avatar
pasde.hcyrano.spam
Philip K. Dick wrote:

Hello

J'ai un programme C++ multi-threadé qui contient plein
de std::cout << "bla bla" << xxx << "bla bla bla" << xxx << std::endl;
(idem avec cerr)

Les traces se mélangent souvent, aussi je cherche un moyen de les
traiter dans un seul thread, tout en minimisant les modifications
du code (par exemple avec une classe xxx exportant une méthode cout/cerr)

Est-ce que cela existe déjà ?

Merci,

PKD


j'avais le meme probleme.

ma solution

ecrire dans des fichiers separés (1 par thread) et visualiser par "tail
-f nomfichier"
--
Bruno Causse
http://perso.wanadoo.fr/othello

Avatar
Philip K. Dick
Philip K. Dick wrote:
Hello

J'ai un programme C++ multi-threadé qui contient plein
de std::cout << "bla bla" << xxx << "bla bla bla" << xxx << std::endl;
(idem avec cerr)

Les traces se mélangent souvent, aussi je cherche un moyen de les
traiter dans un seul thread, tout en minimisant les modifications
du code (par exemple avec une classe xxx exportant une méthode cout/cerr)

Est-ce que cela existe déjà ?


Merci à tous pour vos réponses !