|
a/website/idxthreads/threadingRecoll.txt |
|
b/website/idxthreads/threadingRecoll.txt |
|
... |
|
... |
106 |
|
106 |
|
107 |
|
107 |
|
108 |
The _WorkQueue_ object is implemented by a reasonably simple class, which
|
108 |
The _WorkQueue_ object is implemented by a reasonably simple class, which
|
109 |
manages an input queue on which client append jobs, and a set of worker
|
109 |
manages an input queue on which client append jobs, and a set of worker
|
110 |
threads, which retrieve and perform the jobs, and whose lifetime are
|
110 |
threads, which retrieve and perform the jobs, and whose lifetime are
|
111 |
managed by the _WorkQueue_ object. The
|
111 |
managed by the _WorkQueue_ object. The implementation is straightforward
|
112 |
https://bitbucket.org/medoc/recoll/src/f06f3aba912045d6ad52e9a0fd930b95e363fd10/src/utils/workqueue.h?at=default[implementation] is straightforward with
|
|
|
113 |
*POSIX* threads synchronization functions and C++ *STL* data structures.
|
112 |
with *POSIX* threads synchronization functions and C++ *STL* data
|
|
|
113 |
structures.
|
114 |
|
114 |
|
115 |
In practise it proved quite simple to modify existing code to create a job
|
115 |
In practise it proved quite simple to modify existing code to create a job
|
116 |
object and put it on the queue, instead of calling the downstream routine
|
116 |
object and put it on the queue, instead of calling the downstream routine
|
117 |
with the job parameters, _while keeping the capacity to call the downstream
|
117 |
with the job parameters, _while keeping the capacity to call the downstream
|
118 |
routine directly_. The kind of coupling is determined either by compilation
|
118 |
routine directly_. The kind of coupling is determined either by compilation
|
|
... |
|
... |
173 |
anyway).
|
173 |
anyway).
|
174 |
* Things that need to be protected: sometimes, the best approach is just
|
174 |
* Things that need to be protected: sometimes, the best approach is just
|
175 |
to protect the access with a mutex lock. It is trivial to encapsulate
|
175 |
to protect the access with a mutex lock. It is trivial to encapsulate
|
176 |
the locks in C++ objects to use the "Resource Acquisition is
|
176 |
the locks in C++ objects to use the "Resource Acquisition is
|
177 |
Initialization" idiom, easily making sure that locks are freed when
|
177 |
Initialization" idiom, easily making sure that locks are freed when
|
178 |
exiting the critical section. A very basic
|
178 |
exiting the critical section. Recoll used to include a basic home-made
|
179 |
https://bitbucket.org/medoc/recoll/src/f06f3aba9120/src/utils/ptmutex.h?at=default[example of implementation]
|
179 |
implementation, but now lets C++11 work for it.
|
180 |
can be found in the *Recoll* source code.
|
|
|
181 |
* Things which can stay: this is mostly initialization data such as value
|
180 |
* Things which can stay: this is mostly initialization data such as value
|
182 |
tables which are computed once, and then stay logically constant during
|
181 |
tables which are computed once, and then stay logically constant during
|
183 |
program execution. In order to be sure of a correct single-threaded
|
182 |
program execution. In order to be sure of a correct single-threaded
|
184 |
initialization, it is best to explicitly initialize the modules or
|
183 |
initialization, it is best to explicitly initialize the modules or
|
185 |
functions that use this kind of data in the main thread when the program
|
184 |
functions that use this kind of data in the main thread when the program
|
|
... |
|
... |
375 |
cache. Each filter structure stored in the cache stores a pointer to a
|
374 |
cache. Each filter structure stored in the cache stores a pointer to a
|
376 |
configuration structure. This belonged to the thread which initially
|
375 |
configuration structure. This belonged to the thread which initially
|
377 |
created the filter. But the filter would often be reused by a different
|
376 |
created the filter. But the filter would often be reused by a different
|
378 |
thread, with the consequence that the configuration object was now accessed
|
377 |
thread, with the consequence that the configuration object was now accessed
|
379 |
and modified by two unsynchronized threads... Resetting the config pointer
|
378 |
and modified by two unsynchronized threads... Resetting the config pointer
|
380 |
at the time of filter reuse was the
|
379 |
at the time of filter reuse was a very simple (almost)single-line fix to
|
381 |
https://bitbucket.org/medoc/recoll/commits/943de4b78818079b0eb6ffd0fcbdfdd0746b4a40[ridiculously
|
380 |
this evasive problem.
|
382 |
simple (almost)single-line fix] to this evasive problem.
|
|
|
383 |
|
381 |
|
384 |
Looking at multi-threaded stack dumps is mostly fun for people with several
|
382 |
Looking at multi-threaded stack dumps is mostly fun for people with several
|
385 |
heads, which is unfortunately not my case, so I was quite elated when this
|
383 |
heads, which is unfortunately not my case, so I was quite elated when this
|
386 |
was over.
|
384 |
was over.
|
387 |
|
385 |
|