eyal1.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /* Simple POSIX threads program.
  2. *
  3. *
  4. * --------------------------------------------------------------------------
  5. *
  6. * Pthreads-win32 - POSIX Threads Library for Win32
  7. * Copyright(C) 1998 John E. Bossom
  8. * Copyright(C) 1999,2005 Pthreads-win32 contributors
  9. *
  10. * Contact Email: [email protected]
  11. *
  12. * The current list of contributors is contained
  13. * in the file CONTRIBUTORS included with the source
  14. * code distribution. The list can also be seen at the
  15. * following World Wide Web location:
  16. * http://sources.redhat.com/pthreads-win32/contributors.html
  17. *
  18. * This library is free software; you can redistribute it and/or
  19. * modify it under the terms of the GNU Lesser General Public
  20. * License as published by the Free Software Foundation; either
  21. * version 2 of the License, or (at your option) any later version.
  22. *
  23. * This library is distributed in the hope that it will be useful,
  24. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  26. * Lesser General Public License for more details.
  27. *
  28. * You should have received a copy of the GNU Lesser General Public
  29. * License along with this library in the file COPYING.LIB;
  30. * if not, write to the Free Software Foundation, Inc.,
  31. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  32. *
  33. * --------------------------------------------------------------------------
  34. *
  35. * Author: Eyal Lebedinsky [email protected]
  36. * Written: Sep 1998.
  37. * Version Date: 12 Sep 1998
  38. *
  39. * Do we need to lock stdout or is it thread safe?
  40. *
  41. * Used:
  42. * pthread_t
  43. * pthread_attr_t
  44. * pthread_create()
  45. * pthread_join()
  46. * pthread_mutex_t
  47. * PTHREAD_MUTEX_INITIALIZER
  48. * pthread_mutex_init() [not used now]
  49. * pthread_mutex_destroy()
  50. * pthread_mutex_lock()
  51. * pthread_mutex_trylock()
  52. * pthread_mutex_unlock()
  53. *
  54. * What this program does is establish a work queue (implemented using
  55. * four mutexes for each thread). It then schedules work (by storing
  56. * a number in 'todo') and releases the threads. When the work is done
  57. * the threads will block. The program then repeats the same thing once
  58. * more (just to test the logic) and when the work is done it destroyes
  59. * the threads.
  60. *
  61. * The 'work' we do is simply burning CPU cycles in a loop.
  62. * The 'todo' work queue is trivial - each threads pops one element
  63. * off it by incrementing it, the poped number is the 'work' to do.
  64. * When 'todo' reaches the limit (nwork) the queue is considered
  65. * empty.
  66. *
  67. * The number displayed at the end is the amount of work each thread
  68. * did, so we can see if the load was properly distributed.
  69. *
  70. * The program was written to test a threading setup (not seen here)
  71. * rather than to demonstrate correct usage of the pthread facilities.
  72. *
  73. * Note how each thread is given access to a thread control structure
  74. * (TC) which is used for communicating to/from the main program (e.g.
  75. * the threads knows its 'id' and also filles in the 'work' done).
  76. */
  77. #include "test.h"
  78. #include <stdlib.h>
  79. #include <math.h>
  80. struct thread_control {
  81. int id;
  82. pthread_t thread; /* thread id */
  83. pthread_mutex_t mutex_start;
  84. pthread_mutex_t mutex_started;
  85. pthread_mutex_t mutex_end;
  86. pthread_mutex_t mutex_ended;
  87. long work; /* work done */
  88. int stat; /* pthread_init status */
  89. };
  90. typedef struct thread_control TC;
  91. static TC *tcs = NULL;
  92. static int nthreads = 10;
  93. static int nwork = 100;
  94. static int quiet = 0;
  95. static int todo = -1;
  96. static pthread_mutex_t mutex_todo = PTHREAD_MUTEX_INITIALIZER;
  97. static pthread_mutex_t mutex_stdout = PTHREAD_MUTEX_INITIALIZER;
  98. static void
  99. die (int ret)
  100. {
  101. if (NULL != tcs)
  102. {
  103. free (tcs);
  104. tcs = NULL;
  105. }
  106. if (ret)
  107. exit (ret);
  108. }
  109. static double
  110. waste_time (int n)
  111. {
  112. int i;
  113. double f, g, h, s;
  114. s = 0.0;
  115. /*
  116. * Useless work.
  117. */
  118. for (i = n*100; i > 0; --i)
  119. {
  120. f = rand ();
  121. g = rand ();
  122. h = rand ();
  123. s += 2.0 * f * g / (h != 0.0 ? (h * h) : 1.0);
  124. }
  125. return s;
  126. }
  127. static int
  128. do_work_unit (int who, int n)
  129. {
  130. int i;
  131. static int nchars = 0;
  132. double f = 0.0;
  133. if (quiet)
  134. i = 0;
  135. else {
  136. /*
  137. * get lock on stdout
  138. */
  139. assert(pthread_mutex_lock (&mutex_stdout) == 0);
  140. /*
  141. * do our job
  142. */
  143. i = printf ("%c", "0123456789abcdefghijklmnopqrstuvwxyz"[who]);
  144. if (!(++nchars % 50))
  145. printf ("\n");
  146. fflush (stdout);
  147. /*
  148. * release lock on stdout
  149. */
  150. assert(pthread_mutex_unlock (&mutex_stdout) == 0);
  151. }
  152. n = rand () % 10000; /* ignore incoming 'n' */
  153. f = waste_time (n);
  154. /* This prevents the statement above from being optimised out */
  155. if (f > 0.0)
  156. return(n);
  157. return (n);
  158. }
  159. static int
  160. print_server (void *ptr)
  161. {
  162. int mywork;
  163. int n;
  164. TC *tc = (TC *)ptr;
  165. assert(pthread_mutex_lock (&tc->mutex_started) == 0);
  166. for (;;)
  167. {
  168. assert(pthread_mutex_lock (&tc->mutex_start) == 0);
  169. assert(pthread_mutex_unlock (&tc->mutex_start) == 0);
  170. assert(pthread_mutex_lock (&tc->mutex_ended) == 0);
  171. assert(pthread_mutex_unlock (&tc->mutex_started) == 0);
  172. for (;;)
  173. {
  174. /*
  175. * get lock on todo list
  176. */
  177. assert(pthread_mutex_lock (&mutex_todo) == 0);
  178. mywork = todo;
  179. if (todo >= 0)
  180. {
  181. ++todo;
  182. if (todo >= nwork)
  183. todo = -1;
  184. }
  185. assert(pthread_mutex_unlock (&mutex_todo) == 0);
  186. if (mywork < 0)
  187. break;
  188. assert((n = do_work_unit (tc->id, mywork)) >= 0);
  189. tc->work += n;
  190. }
  191. assert(pthread_mutex_lock (&tc->mutex_end) == 0);
  192. assert(pthread_mutex_unlock (&tc->mutex_end) == 0);
  193. assert(pthread_mutex_lock (&tc->mutex_started) == 0);
  194. assert(pthread_mutex_unlock (&tc->mutex_ended) == 0);
  195. if (-2 == mywork)
  196. break;
  197. }
  198. assert(pthread_mutex_unlock (&tc->mutex_started) == 0);
  199. return (0);
  200. }
  201. static void
  202. dosync (void)
  203. {
  204. int i;
  205. for (i = 0; i < nthreads; ++i)
  206. {
  207. assert(pthread_mutex_lock (&tcs[i].mutex_end) == 0);
  208. assert(pthread_mutex_unlock (&tcs[i].mutex_start) == 0);
  209. assert(pthread_mutex_lock (&tcs[i].mutex_started) == 0);
  210. assert(pthread_mutex_unlock (&tcs[i].mutex_started) == 0);
  211. }
  212. /*
  213. * Now threads do their work
  214. */
  215. for (i = 0; i < nthreads; ++i)
  216. {
  217. assert(pthread_mutex_lock (&tcs[i].mutex_start) == 0);
  218. assert(pthread_mutex_unlock (&tcs[i].mutex_end) == 0);
  219. assert(pthread_mutex_lock (&tcs[i].mutex_ended) == 0);
  220. assert(pthread_mutex_unlock (&tcs[i].mutex_ended) == 0);
  221. }
  222. }
  223. static void
  224. dowork (void)
  225. {
  226. todo = 0;
  227. dosync();
  228. todo = 0;
  229. dosync();
  230. }
  231. int
  232. main (int argc, char *argv[])
  233. {
  234. int i;
  235. assert(NULL != (tcs = (TC *) calloc (nthreads, sizeof (*tcs))));
  236. /*
  237. * Launch threads
  238. */
  239. for (i = 0; i < nthreads; ++i)
  240. {
  241. tcs[i].id = i;
  242. assert(pthread_mutex_init (&tcs[i].mutex_start, NULL) == 0);
  243. assert(pthread_mutex_init (&tcs[i].mutex_started, NULL) == 0);
  244. assert(pthread_mutex_init (&tcs[i].mutex_end, NULL) == 0);
  245. assert(pthread_mutex_init (&tcs[i].mutex_ended, NULL) == 0);
  246. tcs[i].work = 0;
  247. assert(pthread_mutex_lock (&tcs[i].mutex_start) == 0);
  248. assert((tcs[i].stat =
  249. pthread_create (&tcs[i].thread,
  250. NULL,
  251. (void *(*)(void *))print_server,
  252. (void *) &tcs[i])
  253. ) == 0);
  254. /*
  255. * Wait for thread initialisation
  256. */
  257. {
  258. int trylock = 0;
  259. while (trylock == 0)
  260. {
  261. trylock = pthread_mutex_trylock(&tcs[i].mutex_started);
  262. assert(trylock == 0 || trylock == EBUSY);
  263. if (trylock == 0)
  264. {
  265. assert(pthread_mutex_unlock (&tcs[i].mutex_started) == 0);
  266. }
  267. }
  268. }
  269. }
  270. dowork ();
  271. /*
  272. * Terminate threads
  273. */
  274. todo = -2; /* please terminate */
  275. dosync();
  276. for (i = 0; i < nthreads; ++i)
  277. {
  278. if (0 == tcs[i].stat)
  279. assert(pthread_join (tcs[i].thread, NULL) == 0);
  280. }
  281. /*
  282. * destroy locks
  283. */
  284. assert(pthread_mutex_destroy (&mutex_stdout) == 0);
  285. assert(pthread_mutex_destroy (&mutex_todo) == 0);
  286. /*
  287. * Cleanup
  288. */
  289. printf ("\n");
  290. /*
  291. * Show results
  292. */
  293. for (i = 0; i < nthreads; ++i)
  294. {
  295. printf ("%2d ", i);
  296. if (0 == tcs[i].stat)
  297. printf ("%10ld\n", tcs[i].work);
  298. else
  299. printf ("failed %d\n", tcs[i].stat);
  300. assert(pthread_mutex_unlock(&tcs[i].mutex_start) == 0);
  301. assert(pthread_mutex_destroy (&tcs[i].mutex_start) == 0);
  302. assert(pthread_mutex_destroy (&tcs[i].mutex_started) == 0);
  303. assert(pthread_mutex_destroy (&tcs[i].mutex_end) == 0);
  304. assert(pthread_mutex_destroy (&tcs[i].mutex_ended) == 0);
  305. }
  306. die (0);
  307. return (0);
  308. }