File: tut8.html

package info (click to toggle)
libcwd 1.0.4-1.1
  • links: PTS
  • area: non-free
  • in suites: jessie, jessie-kfreebsd
  • size: 8,136 kB
  • ctags: 10,313
  • sloc: cpp: 23,354; sh: 9,798; ansic: 1,172; makefile: 852; exp: 234; awk: 11
file content (206 lines) | stat: -rw-r--r-- 8,154 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML LANG="en-us">
<HEAD>
<META name="Author" content="Carlo Wood">
<META http-equiv="content-type" content="text/html; charset=iso-8859-1">
<META http-equiv="content-script-type" content="text/javascript">
<TITLE>libcwd: The C++ Debugging Support Library - Tutorial</TITLE>
<SCRIPT SRC="../scripts/detect_browser.js"></SCRIPT>
<SCRIPT>need_style_tutorial=1</SCRIPT>
<SCRIPT SRC="../scripts/load_style_sheets.js"></SCRIPT>
</HEAD>
<BODY>

<TABLE class="header" height=64 width="100%" cellpadding=0 cellspacing=0 border=0>
  <TR>
    <TD width=237 valign=top>
      <IMG valign=top src="../images/libcwd_logo.png" alt="" align=left border=0>
    </TD>
    <TD width="100%" align=center>
      <DIV class="header-title">
      The C++ Debugging Support Library
      </DIV>
      <DIV class="header-copyright">
      By Carlo Wood, &copy;1999 - 2003.
      </DIV>
    </TD>
  </TR>
  <SCRIPT>if (is_mozilla4) document.write("<TR><TD colspan=2 height=19 valign=bottom><HR SIZE=2 NOSHADE></TD></TR>");</SCRIPT>
</TABLE>

<DIV class="body">

<H2>Tutorial 8: Debugging Threaded Applications</H2>

<P>When debugging a threaded application, you must link with -lcwd_r instead of -lcwd.&nbsp;
For example:</P>

<PRE>
g++ -pthread -DLIBCWD_THREAD_SAFE -DCWDEBUG program.cc -lpthread -lcwd_r
</PRE>

<P>Best practise is to use the tool <CODE>pkg-config</CODE> to retrieve the
flags that one needs to pass to the compiler and linker. That is, the output
of <CODE>pkg-config --cflags libcwd_r</CODE> and <CODE>pkg-config --libs libcwd_r</CODE>.</P>

<P>Libcwd_r should be completely thread-safe, with the following restrictions:</P>
<UL>
<LI>All debug objects and debug channels <EM>must</EM> be global (as they should
be in non-threaded applications for that matter).</LI>
<LI>You are not allowed to create threads before all static and global objects
are initialized; in practise this means that you are not allowed to create threads
until <CODE>main()</CODE> is reached.</LI>
<LI>You cannot use <CODE>dlopen()</CODE> to load libcwd when threads have
already been created.&nbsp; Likewise you shouldn't <CODE>dlopen()</CODE>
other libraries that use libcwd when there are already running threads,
especially when those libraries define new debug objects and/or channels.</LI>
<LI>You need to provide one and only one locking mechanism per ostream device
that is also used to write debug output.&nbsp; It is preferable not to
use the same ostream with two or more different debug objects.</LI>
</UL>

<P>Essentially the debug objects and channels react towards each thread as if
that thread is the only thread.&nbsp; The only (visible) shared variable is
the final <CODE>ostream</CODE> that a given debug object writes to.&nbsp;
This means that if one thread changes the <CODE>ostream</CODE> then all other
threads also suddenly start to write to that <CODE>ostream</CODE>.&nbsp;
Basically, it is simply not supported: don't change the output stream
on the fly.</P>

<P>All other characteristics like the on/off state and the margin and
marker strings as well as the indentation are Thread Specific: Every
thread may change those without locking or worrying about the effect on
other threads.</P>

<P>Every time a new thread is created, it will start with all debug objects
and channels turned off, just as at the start of <CODE>main()</CODE>.</P>

<P>In all likelihood, you'd want to set the margin string such that it reflects which
thread is printing the output.&nbsp; For example:</P>

<PRE>
#include "sys.h"	// See <A HREF="../reference-manual/preparation.html">documentation/reference-manual/preparation.html</A>
#include "debug.h"
#include &lt;iostream&gt;
#include &lt;cstdio&gt;
#include &lt;pthread.h&gt;

void* thread_function(void* arguments)
{
  // Set Thread Specific on/off flags of the debug channels.
  ForAllDebugChannels( if (!debugChannel.is_on()) debugChannel.on(); );
  // And for the debug object.
  Debug( libcw_do.on() );
  // Set a margin.
#ifdef CWDEBUG
  char margin[16];
  sprintf(margin, "%-10lu ", pthread_self());
#endif
  Debug( libcw_do.margin().assign(margin, 11) );

  Dout(dc::notice, "Entering thread " &lt;&lt; pthread_self());
  // ... do stuff
  Dout(dc::notice, "Leaving thread " &lt;&lt; pthread_self());
  return (void*)true;
}

#ifdef CWDEBUG
pthread_mutex_t cout_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif

int main(void)
{
  // Don't output a single character at a time (yuk)
  // (Read <A HREF ="http://gcc.gnu.org/onlinedocs/libstdc++/27_io/howto.html#8">http://gcc.gnu.org/onlinedocs/libstdc++/27_io/howto.html#8</A> for an explanation.)
  Debug(set_invisible_on());
  std::ios::sync_with_stdio(false);	// Cause "memory leaks" ([w]cin, [w]cout, [w]cerr filebuf allocations).
  Debug(set_invisible_off());
  // Do header files and library match?
  Debug( check_configuration() );
  // Send debug output to std::cout.
  Debug( libcw_do.set_ostream(&std::cout, &cout_mutex) );
  // Turn debug object on.
  Debug( libcw_do.on() );
  // Set a margin.
#ifdef CWDEBUG
  char margin[16];
  sprintf(margin, "%-10lu ", pthread_self());
#endif
  Debug( libcw_do.margin().assign(margin, 11) );
  // Turn all debug channels on.
  ForAllDebugChannels( if (!debugChannel.is_on()) debugChannel.on(); );
  // List all channels.
  Debug( list_channels_on(libcw_do) );

  // Create and join a few threads...
  int const number_of_threads = 4;
  pthread_t thread_id[number_of_threads];
  for (int i = 0; i &lt; number_of_threads; ++i)
  {
    Dout(dc::notice|continued_cf, "main: creating thread " &lt;&lt; i &lt;&lt; ", ");
    pthread_create(&thread_id[i], NULL, thread_function, NULL);
    Dout(dc::finish, "id " &lt;&lt; thread_id[i] &lt;&lt; '.');
  }

  for (int i = 0; i &lt; number_of_threads; ++i)
  {
    void* status;
    pthread_join(thread_id[i], &status);
    Dout(dc::notice, "main loop: thread " &lt;&lt; i &lt;&lt; ", id " &lt;&lt; thread_id[i] &lt;&lt;
         ", returned with status " &lt;&lt; ((bool)status ? "OK" : "ERROR") &lt;&lt; '.');
  }

  Dout(dc::notice, "Exiting from main()");
  return 0;
}
</PRE>

<P>Which outputs something like:</P>

<PRE class="output">
1024       BFD     : Enabled
1024       DEBUG   : Enabled
1024       MALLOC  : Enabled
1024       NOTICE  : Enabled
1024       SYSTEM  : Enabled
1024       WARNING : Enabled
1024       NOTICE  : main: creating thread 0, &lt;unfinished&gt;
1024       MALLOC  :     malloc(8160) = &lt;unfinished&gt;
1024       BFD     :         address 0x401fbbd8 corresponds to pthread.c:533
1024       MALLOC  :     &lt;continued> 0x8386890
1024       NOTICE  : &lt;continued&gt; id 1026.
1026       NOTICE  : Entering thread 1026
1026       NOTICE  : Leaving thread 1026
1024       NOTICE  : main: creating thread 1, id 2051.
2051       NOTICE  : Entering thread 2051
2051       NOTICE  : Leaving thread 2051
1024       NOTICE  : main: creating thread 2, id 3076.
3076       NOTICE  : Entering thread 3076
3076       NOTICE  : Leaving thread 3076
1024       NOTICE  : main: creating thread 3, id 4101.
1024       NOTICE  : main loop: thread 0, id 1026, returned with status OK.
1024       NOTICE  : main loop: thread 1, id 2051, returned with status OK.
1024       NOTICE  : main loop: thread 2, id 3076, returned with status OK.
4101       NOTICE  : Entering thread 4101
4101       NOTICE  : Leaving thread 4101
1024       NOTICE  : main loop: thread 3, id 4101, returned with status OK.
1024       NOTICE  : Exiting from main()
1024       MALLOC  : free(0x8386890)            pthread.c:533  &lt;unknown type&gt;; (sz = 8160)
</PRE>

<P>Congratulations, you are now a libcwd expert.&nbsp; If you still have any
questions that you can't find answers to here, feel free to mail me.</P>


</DIV>
<P class="line"><IMG width=870 height=25 src="../images/lines/owl.png"></P>
<DIV class="buttons">
<A HREF="tut7.html"><IMG width=64 height=32 src="../images/buttons/lr_prev.png" border="0"></A>
<A HREF="index.html"><IMG width=64 height=32 src="../images/buttons/lr_index.png" border="0"></A>
</DIV>

<ADDRESS>Copyright &copy; 2001, 2002 Carlo Wood.&nbsp; All rights reserved.</ADDRESS>

</BODY>
</HTML>