source: trunk/third/gstreamer/docs/manual/advanced-threads.xml @ 21448

Revision 21448, 9.4 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21447, which included commits to RCS files with non-trunk default branches.
Line 
1<chapter id="chapter-threads">
2  <title>Threads</title>
3  <para>
4    GStreamer has support for multithreading through the use of
5    the <ulink type="http"
6    url="&URLAPI;GstThread.html"><classname>GstThread</classname></ulink>
7    object. This object is in fact a special <ulink type="http"
8    url="&URLAPI;GstBin.html"><classname>GstBin</classname></ulink>
9    that will start a new thread (using Glib's
10    <classname>GThread</classname> system) when started.
11  </para>
12  <para>
13    To create a new thread, you can simply use <function>gst_thread_new
14    ()</function>. From then on, you can use it similar to how you would
15    use a <classname>GstBin</classname>. You can add elements to it,
16    change state and so on. The largest difference between a thread and
17    other bins is that the thread does not require iteration. Once set to
18    the <classname>GST_STATE_PLAYING</classname> state, it will iterate
19    its contained children elements automatically.
20  </para>
21  <para>
22    <xref linkend="section-threads-img"/> shows how a thread can be
23    visualised.
24  </para>
25  <figure float="1" id="section-threads-img">
26    <title>A thread</title>
27    <mediaobject>
28      <imageobject>
29        <imagedata fileref="images/thread.&image;" format="&IMAGE;"/>
30      </imageobject>
31    </mediaobject>
32  </figure>
33
34  <sect1 id="section-threads-uses">
35    <title>When would you want to use a thread?</title>
36    <para>
37      There are several reasons to use threads. However, there's also some
38      reasons to limit the use of threads as much as possible. We will go
39      into the drawbacks of threading in &GStreamer; in the next section.
40      Let's first list some situations where threads can be useful:
41    </para>
42    <itemizedlist>
43      <listitem>
44        <para>
45          Data buffering, for example when dealing with network streams or
46          when recording data from a live stream such as a video or audio
47          card. Short hickups elsewhere in the pipeline will not cause data
48          loss. See <xref linkend="section-queues-img"/> for a visualization
49          of this idea.
50        </para>
51      </listitem>
52      <listitem>
53        <para>
54          Synchronizing output devices, e.g. when playing a stream containing
55          both video and audio data. By using threads for both outputs, they
56          will run independently and their synchronization will be better.
57        </para>
58      </listitem>
59      <listitem>
60        <para>
61          Data pre-rolls. You can use threads and queues (thread boundaries)
62          to cache a few seconds of data before playing. By using this
63          approach, the whole pipeline will already be setup and data will
64          already be decoded. When activating the rest of the pipeline, the
65          switch from PAUSED to PLAYING will be instant.
66        </para>
67      </listitem>
68    </itemizedlist>
69    <figure float="1" id="section-queues-img">
70      <title>a two-threaded decoder with a queue</title>
71      <mediaobject>
72        <imageobject>
73          <imagedata fileref="images/queue.&image;" format="&IMAGE;"/>
74        </imageobject>
75      </mediaobject>
76    </figure>
77    <para>
78      Above, we've mentioned the <quote>queue</quote> element several times
79      now. A queue is a thread boundary element. It does so by using a
80      classic provider/receiver model as learned in threading classes at
81      universities all around the world. By doing this, it acts both as a
82      means to make data throughput between threads threadsafe, and it can
83      also act as a buffer. Queues have several <classname>GObject</classname>
84      properties to be configured for specific uses. For example, you can set
85      lower and upper tresholds for the element. If there's less data than
86      the lower treshold (default: disabled), it will block output. If
87      there's more data than the upper treshold, it will block input or
88      (if configured to do so) drop data.
89    </para>
90  </sect1>
91
92  <sect1 id="section-threads-constraints">
93    <title>Constraints placed on the pipeline by the GstThread</title>
94    <para>
95      Within the pipeline, everything is the same as in any other bin. The
96      difference lies at the thread boundary, at the link between the
97      thread and the outside world (containing bin). Since &GStreamer; is
98      fundamentally buffer-oriented rather than byte-oriented, the natural
99      solution to this problem is an element that can "buffer" the buffers
100      between the threads, in a thread-safe fashion. This element is the
101      <quote>queue</quote> element. A queue should be placed in between any
102      two elements whose pads are linked together while the elements live in
103      different threads. It doesn't matter if the queue is placed in the
104      containing bin or in the thread itself, but it needs to be present
105      on one side or the other to enable inter-thread communication.
106    </para>
107    <para>
108      If you are writing a GUI application, making the top-level bin a
109      thread will make your GUI more responsive. If it were a pipeline
110      instead, it would have to be iterated by your application's event
111      loop, which increases the latency between events (say, keyboard
112      presses) and responses from the GUI. In addition, any slight hang
113      in the GUI would delay iteration of the pipeline, which (for example)
114      could cause pops in the output of the sound card, if it is an audio
115      pipeline.
116    </para>
117    <para>
118      A problem with using threads is, however, thread contexts. If you
119      connect to a signal that is emitted inside a thread, then the signal
120      handler for this thread <emphasis>will be executed in that same
121      thread</emphasis>! This is very important to remember, because many
122      graphical toolkits can not run multi-threaded. Gtk+, for example,
123      only allows threaded access to UI objects if you explicitely use
124      mutexes. Not doing so will result in random crashes and X errors.
125      A solution many people use is to place an idle handler in the signal
126      handler, and have the actual signal emission code be executed in the
127      idle handler, which will be executed from the mainloop.
128    </para>
129    <para>
130      Generally, if you use threads, you will encounter some problems. Don't
131      hesistate to ask us for help in case of problems.
132    </para>
133  </sect1>
134
135  <sect1 id="section-threads-example">
136    <title>A threaded example application</title>
137    <para>
138      As an example we show the helloworld program that we coded in
139      <xref linkend="chapter-helloworld"/> using a thread. Note that
140      the whole application lives in a thread (as opposed to half
141      of the application living in a thread and the other half being
142      another thread or a pipeline). Therefore, it does not need a
143      queue element in this specific case.
144    </para>
145 
146    <programlisting><!-- example-begin threads.c -->
147#include &lt;gst/gst.h&gt;
148
149GstElement *thread, *source, *decodebin, *audiosink;
150
151static gboolean
152idle_eos (gpointer data)
153{
154  g_print ("Have idle-func in thread %p\n", g_thread_self ());
155  gst_main_quit ();
156
157  /* do this function only once */
158  return FALSE;
159}
160
161/*
162 * EOS will be called when the src element has an end of stream.
163 * Note that this function will be called in the thread context.
164 * We will place an idle handler to the function that really
165 * quits the application.
166 */
167static void
168cb_eos (GstElement *thread,
169        gpointer    data)
170{
171  g_print ("Have eos in thread %p\n", g_thread_self ());
172  g_idle_add ((GSourceFunc) idle_eos, NULL);
173}
174
175/*
176 * On error, too, you'll want to forward signals to the main
177 * thread, especially when using GUI applications.
178 */
179
180static void
181cb_error (GstElement *thread,
182          GstElement *source,
183          GError     *error,
184          gchar      *debug,
185          gpointer    data)
186{
187  g_print ("Error in thread %p: %s\n", g_thread_self (), error->message);
188  g_idle_add ((GSourceFunc) idle_eos, NULL);
189}
190
191/*
192 * Link new pad from decodebin to audiosink.
193 * Contains no further error checking.
194 */
195
196static void
197cb_newpad (GstElement *decodebin,
198           GstPad     *pad,
199           gboolean    last,
200           gpointer    data)
201{
202  gst_pad_link (pad, gst_element_get_pad (audiosink, "sink"));
203  gst_bin_add (GST_BIN (thread), audiosink);
204  gst_bin_sync_children_state (GST_BIN (thread));
205}
206
207gint
208main (gint   argc,
209      gchar *argv[])
210{
211  /* init GStreamer */
212  gst_init (&amp;argc, &amp;argv);
213
214  /* make sure we have a filename argument */
215  if (argc != 2) {
216    g_print ("usage: %s &lt;Ogg/Vorbis filename&gt;\n", argv[0]);
217    return -1;
218  }
219
220  /* create a new thread to hold the elements */
221  thread = gst_thread_new ("thread");
222  g_signal_connect (thread, "eos", G_CALLBACK (cb_eos), NULL);
223  g_signal_connect (thread, "error", G_CALLBACK (cb_error), NULL);
224
225  /* create elements */
226  source = gst_element_factory_make ("filesrc", "source");
227  g_object_set (G_OBJECT (source), "location", argv[1], NULL);
228  decodebin = gst_element_factory_make ("decodebin", "decoder");
229  g_signal_connect (decodebin, "new-decoded-pad",
230                    G_CALLBACK (cb_newpad), NULL);
231  audiosink = gst_element_factory_make ("alsasink", "audiosink");
232
233  /* setup */
234  gst_bin_add_many (GST_BIN (thread), source, decodebin, NULL);
235  gst_element_link (source, decodebin);
236  gst_element_set_state (audiosink, GST_STATE_PAUSED);
237  gst_element_set_state (thread, GST_STATE_PLAYING);
238
239  /* no need to iterate. We can now use a mainloop */
240  gst_main ();
241
242  /* unset */
243  gst_element_set_state (thread, GST_STATE_NULL);
244  gst_object_unref (GST_OBJECT (thread));
245
246  return 0;
247}
248    <!-- example-end threads.c --></programlisting>
249  </sect1>
250</chapter>
Note: See TracBrowser for help on using the repository browser.