You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

259 lines
6.3 KiB

2 months ago
  1. /* multiseed.c (multithreading demo) */
  2. /***********************************************************************
  3. * This code is part of GLPK (GNU Linear Programming Kit).
  4. *
  5. * Author: Heinrich Schuchardt <xypron.glpk@gmx.de>
  6. *
  7. * Copyright (C) 2017 Andrew Makhorin, Department for Applied
  8. * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
  9. * reserved. E-mail: <mao@gnu.org>.
  10. *
  11. * GLPK is free software: you can redistribute it and/or modify it
  12. * under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation, either version 3 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * GLPK is distributed in the hope that it will be useful, but WITHOUT
  17. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  18. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  19. * License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  23. ***********************************************************************/
  24. /*
  25. * This program demonstrates running the GLPK library with multiple threads.
  26. *
  27. * When called the program requires two arguments:
  28. *
  29. * filename - the name of the MathProg model to be solved
  30. * threads - the count of parallel threads to be run.
  31. *
  32. * Each thread is run with a different seed for the random number generator
  33. * provided by the GLPK library.
  34. */
  35. #include <glpk.h>
  36. #include <malloc.h>
  37. #include <setjmp.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include "thread.h"
  42. #define BUFLEN 256
  43. /* Task descriptor */
  44. struct task {
  45. pthread_t tid;
  46. char *filename;
  47. int seed;
  48. size_t pos;
  49. char buf[BUFLEN + 1];
  50. int line;
  51. jmp_buf jmp;
  52. };
  53. /* Mutex for console output */
  54. pthread_mutex_t mutex;
  55. /* Console output handler */
  56. int term_hook(void *info, const char *text)
  57. {
  58. struct task *task = (struct task *) info;
  59. size_t len = strlen(text);
  60. /* Lock mutex so this is the only task creating console output. */
  61. pthread_mutex_lock(&mutex);
  62. /* Append the new text to the buffer. */
  63. if (task->pos + len > BUFLEN) {
  64. printf("%02d-%05d %s%s", task->seed, ++task->line, task->buf, text);
  65. task->pos = 0;
  66. task->buf[0] = 0;
  67. } else {
  68. strcpy(task->buf + task->pos, text);
  69. task->pos += len;
  70. }
  71. /* If a complete line is available, send it to the console. */
  72. if (strchr(task->buf, '\n')) {
  73. printf("%02d-%05d %s", task->seed, ++task->line, task->buf);
  74. task->pos = 0;
  75. task->buf[0] = 0;
  76. }
  77. /* Unlock the mutex. */
  78. pthread_mutex_unlock(&mutex);
  79. /* Disable default output. */
  80. return -1;
  81. }
  82. /* Error handler */
  83. void error_hook(void *info)
  84. {
  85. struct task *task = (struct task *) info;
  86. term_hook(task, "Error caught\n");
  87. glp_free_env();
  88. longjmp(task->jmp, 1);
  89. }
  90. void worker(void *arg)
  91. {
  92. struct task *task = (struct task *) arg;
  93. int ret;
  94. glp_prob *lp;
  95. glp_tran *tran;
  96. glp_iocp iocp;
  97. if (setjmp(task->jmp)) {
  98. /* If an error is caught leave the function. */
  99. return;
  100. }
  101. /* Set the error handler. */
  102. glp_error_hook(error_hook, task);
  103. /* Set the console output handler. */
  104. glp_term_hook(term_hook, arg);
  105. glp_printf("Seed %02d\n", task->seed);
  106. /* Create the problem object. */
  107. lp = glp_create_prob();
  108. if (!lp) {
  109. glp_error("Out of memory\n");
  110. }
  111. /* Create the MathProg translator workspace. */
  112. tran = glp_mpl_alloc_wksp();
  113. if (!lp) {
  114. glp_error("Out of memory\n");
  115. }
  116. /* Set the pseudo random number generator seed. */
  117. glp_mpl_init_rand(tran, task->seed);
  118. /* Read the model file. */
  119. ret = glp_mpl_read_model (tran, task->filename, GLP_OFF);
  120. if (ret != 0) {
  121. glp_error("Model %s is not valid\n", task->filename);
  122. }
  123. /* Generate the model. */
  124. ret = glp_mpl_generate(tran, NULL);
  125. if (ret != 0) {
  126. glp_error("Cannot generate model %s\n", task->filename);
  127. }
  128. /* Build the problem. */
  129. glp_mpl_build_prob(tran, lp);
  130. /* Solve the problem. */
  131. glp_init_iocp(&iocp);
  132. iocp.presolve = GLP_ON;
  133. ret = glp_intopt(lp, &iocp);
  134. if (ret == 0) {
  135. /* Execute the post solve part of the model. */
  136. glp_mpl_postsolve(tran, lp, GLP_MIP);
  137. }
  138. /* Release the memory. */
  139. glp_mpl_free_wksp (tran);
  140. glp_delete_prob(lp);
  141. if (0 == task->seed % 3) {
  142. glp_error("Voluntarily throwing an error in %s at line %d\n",
  143. __FILE__, __LINE__);
  144. }
  145. glp_term_hook(NULL, NULL);
  146. glp_error_hook(NULL, NULL);
  147. glp_free_env();
  148. }
  149. #ifdef __WOE__
  150. DWORD run(void *arg)
  151. {
  152. #else
  153. void *run(void *arg)
  154. {
  155. #endif
  156. worker(arg);
  157. pthread_exit(NULL);
  158. }
  159. int main(int argc, char *argv[])
  160. {
  161. int i, n, rc;
  162. struct task *tasks;
  163. /* Make sure thread local memory is used by the GLPK library. */
  164. if (!glp_config("TLS")) {
  165. printf("The loaded GLPK library does not support thread local memory.\n"
  166. "You need a version of the library configured with "
  167. "--enable-reentrant=yes to run this program.\n");
  168. exit(EXIT_FAILURE);
  169. }
  170. /* Check program arguments. */
  171. if (argc != 3) {
  172. printf("Usage %s filename threads\n"
  173. " filename - MathProg model file\n"
  174. " threads - number of threads\n",
  175. argv[0]);
  176. exit(EXIT_FAILURE);
  177. }
  178. /* Parse the arguments. */
  179. n = atoi(argv[2]);
  180. if (n > 50) {
  181. printf("Number of threads is to high (> 50).\n");
  182. exit(EXIT_FAILURE);
  183. }
  184. if (n <= 1) {
  185. printf("Need positive number of threads\n");
  186. exit(EXIT_FAILURE);
  187. }
  188. /* Allocate memory for the task descriptors. */
  189. tasks = calloc(n, sizeof(struct task));
  190. if (!tasks) {
  191. printf("Out of memory");
  192. exit(EXIT_FAILURE);
  193. }
  194. /* Create a mutex for console output. */
  195. pthread_mutex_init(&mutex, NULL);
  196. /* Create the threads. */
  197. for (i = 0; i < n; ++i) {
  198. tasks[i].filename = argv[1];
  199. tasks[i].seed = i + 1;
  200. tasks[i].pos = 0;
  201. tasks[i].buf[0] = 0;
  202. tasks[i].line = 0;
  203. rc = pthread_create(&tasks[i].tid, NULL, run, &tasks[i]);
  204. if (rc) {
  205. printf("ERROR; return code from pthread_create() is %d\n", rc);
  206. exit(EXIT_FAILURE);
  207. }
  208. }
  209. /* Wait for all threads to complete. */
  210. for (i = 0; i < n; ++i) {
  211. pthread_join(tasks[i].tid, NULL);
  212. }
  213. /* Destroy the mutex. */
  214. pthread_mutex_destroy(&mutex);
  215. return EXIT_SUCCESS;
  216. }