>From 50f91c868e803b0519be2bae1862d1742dec9afa Mon Sep 17 00:00:00 2001
From: Heinrich Schuchardt
Date: Tue, 10 Jan 2017 22:37:54 +0100
Subject: [PATCH 1/1] Add multithreading example
Signed-off-by: Heinrich Schuchardt
---
examples/tls/Makefile | 5 +
examples/tls/clustering.mod | 109 +++++++++++++++++++++
examples/tls/multiseed.c | 226 ++++++++++++++++++++++++++++++++++++++++++++
examples/tls/thread.h | 53 +++++++++++
4 files changed, 393 insertions(+)
create mode 100644 examples/tls/Makefile
create mode 100644 examples/tls/clustering.mod
create mode 100644 examples/tls/multiseed.c
create mode 100644 examples/tls/thread.h
diff --git a/examples/tls/Makefile b/examples/tls/Makefile
new file mode 100644
index 0000000..61063d3
--- /dev/null
+++ b/examples/tls/Makefile
@@ -0,0 +1,5 @@
+all:
+ gcc multiseed.c -I. -lglpk -pthread -o multiseed
+
+check:
+ ./multiseed clustering.mod 20
diff --git a/examples/tls/clustering.mod b/examples/tls/clustering.mod
new file mode 100644
index 0000000..21c17b0
--- /dev/null
+++ b/examples/tls/clustering.mod
@@ -0,0 +1,109 @@
+/*
+ * Author: Heinrich Schuchardt
+ *
+ * This model solves a clustering problem:
+ *
+ * Out of 50 towns select 3 to be cluster centers and assign the other
+ * towns to the clusters such that the sum of the population weighted
+ * euclidian distances between towns and centers is minimized.
+ *
+ * The solution is saved as a scalable vector graphic file with a
+ * pseudo-random file name.
+ */
+
+# Output file
+param fn, symbolic := "00000" & 100000 * Uniform01();
+param f, symbolic := "ct" & substr(fn, length(fn) - 4) & ".svg";
+
+# Centers
+param nc := 3;
+set C := {1 .. nc};
+
+# Towns
+param nt := 50;
+set T := {1 .. nt};
+param xt{T} := Uniform01();
+param yt{T} := Uniform01();
+param pt{T} := ceil(1000 * Uniform01());
+
+# Image size
+param scale := 1000;
+
+# Colors
+# saturation [0, 255]
+param sat := 192;
+param hue{c in C} := 6 * (c - 1) / nc;
+param red{c in C} :=
+ if hue[c] <= 1 or hue[c] >= 5 then 255
+ else (if hue[c] >=2 and hue[c] <= 4 then 255 - sat
+ else (if hue[c] <=2 then 255 - sat + sat * (2-hue[c])
+ else 255 - sat + sat * (hue[c]-4) ));
+param green{c in C} :=
+ if hue[c] >= 1 and hue[c] <= 3 then 255
+ else (if hue[c] >= 4 then 255 - sat
+ else (if hue[c] <=1 then 255 - sat + sat * hue[c]
+ else 255 - sat + sat * (4-hue[c]) ));
+param blue{c in C} :=
+ if hue[c] >= 3 and hue[c] <= 5 then 255
+ else (if hue[c] <=2 then 255 - sat
+ else (if hue[c] <=3 then 255 - sat + sat * (hue[c]-2)
+ else 255 - sat + sat * (6-hue[c]) ));
+
+var x{T};
+var y{T,T}, binary;
+
+minimize obj : sum{c in T, t in T} y[c,t] * pt[t]
+ * sqrt((xt[c] - xt[t])^2 + (yt[c] - yt[t])^2);
+
+s.t. sumx : sum{c in T} x[c] = nc;
+s.t. cxy{c in T, t in T} : y[c,t] <= x[c];
+s.t. sumy{t in T} : sum{c in T} y[c,t] = 1;
+
+solve;
+
+for {c in T : x[c] > .5} {
+ printf "Center %5.4f %5.4f\n", xt[c], yt[c];
+ for {t in T : y[c,t] > .5} {
+ printf " Town %5.4f %5.4f (%5.0f)\n", xt[t], yt[t], pt[t];
+ }
+}
+
+# Output the solution as scalable vector graphic
+
+# header
+printf "\n" > f;
+printf "> f;
+printf """http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"">\n" >> f;
+printf "\n" >> f;
+
+end;
diff --git a/examples/tls/multiseed.c b/examples/tls/multiseed.c
new file mode 100644
index 0000000..68a4344
--- /dev/null
+++ b/examples/tls/multiseed.c
@@ -0,0 +1,226 @@
+/* multiseed.d (multithreading demo) */
+
+/***********************************************************************
+*
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Author: Heinrich Schuchardt
+*
+* Copyright (C) 2000-2017 Andrew Makhorin, Department for Applied
+* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
+* reserved. E-mail: .
+*
+* GLPK is free software: you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* GLPK is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+* License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with GLPK. If not, see .
+***********************************************************************/
+
+/*
+ * This program demonstrates running the GLPK library with multiple threads.
+ *
+ * When called the program requires two arguments:
+ *
+ * filename - the name of the MathProg model to be solved
+ * threads - the count of parallel threads to be run.
+ *
+ * Each thread is run with a different seed for the random number generator
+ * provided by the GLPK library.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "thread.h"
+
+#define BUFLEN 256
+
+struct task {
+ pthread_t tid;
+ char *filename;
+ int seed;
+ size_t pos;
+ char buf[BUFLEN + 1];
+ int line;
+ jmp_buf jmp;
+};
+
+pthread_mutex_t mutex;
+
+int term_hook(void *info, const char *text)
+{
+ struct task *task = (struct task *) info;
+ size_t len = strlen(text);
+ char *pos;
+
+ pthread_mutex_lock(&mutex);
+ if (task->pos + len > BUFLEN) {
+ printf("%02d-%05d %s%s", task->seed, ++task->line, task->buf, text);
+ task->pos = 0;
+ task->buf[0] = 0;
+ } else {
+ strcpy(task->buf + task->pos, text);
+ task->pos += len;
+ }
+ if (strchr(task->buf, '\n')) {
+ printf("%02d-%05d %s", task->seed, ++task->line, task->buf);
+ task->pos = 0;
+ task->buf[0] = 0;
+ }
+ pthread_mutex_unlock(&mutex);
+ return -1;
+}
+
+void error_hook(void *info)
+{
+ struct task *task = (struct task *) info;
+
+ term_hook(task, "Error caught\n");
+ glp_free_env();
+ longjmp(task->jmp, 1);
+}
+
+void worker(void *arg)
+{
+ struct task *task = (struct task *) arg;
+ int ret;
+ glp_prob *lp;
+ glp_tran *tran;
+ glp_iocp iocp;
+
+ glp_error_hook(error_hook, task);
+
+ if (setjmp(task->jmp)) {
+ return;
+ }
+
+ glp_term_hook(term_hook, arg);
+
+ glp_printf("Seed %02d\n", task->seed);
+
+ lp = glp_create_prob();
+ tran = glp_mpl_alloc_wksp();
+ glp_mpl_init_rand(tran, task->seed);
+
+ ret = glp_mpl_read_model (tran, task->filename, GLP_OFF);
+ if (ret != 0) {
+ glp_mpl_free_wksp (tran);
+ glp_delete_prob(lp);
+ glp_printf("Model %s not valid\n", task->filename);
+ glp_free_env();
+ }
+
+ ret = glp_mpl_generate(tran, NULL);
+ if (ret != 0) {
+ glp_mpl_free_wksp (tran);
+ glp_delete_prob(lp);
+ glp_printf("Cannot generate model %s\n", task->filename);
+ glp_free_env();
+ }
+
+ glp_mpl_build_prob(tran, lp);
+
+ glp_init_iocp(&iocp);
+ iocp.presolve = GLP_ON;
+
+ ret = glp_intopt(lp, &iocp);
+
+ if (ret == 0) {
+ glp_mpl_postsolve(tran, lp, GLP_MIP);
+ }
+
+ glp_mpl_free_wksp (tran);
+ glp_delete_prob(lp);
+
+ if (0 == task->seed % 3) {
+ glp_error("Voluntarily throwing an error in %s at line %d\n",
+ __FILE__, __LINE__);
+ }
+
+ glp_term_hook(NULL, NULL);
+
+ glp_error_hook(NULL, NULL);
+
+ glp_free_env();
+}
+
+#ifdef __WOE__
+DWORD run(void *arg)
+{
+#else
+void *run(void *arg)
+{
+#endif
+ worker(arg);
+ pthread_exit(NULL);
+#ifdef __WOE__
+ return 0;
+#else
+ return NULL;
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ pthread_t t;
+ int i, n, rc;
+ struct task *tasks;
+
+ if (argc != 3) {
+ printf("Usage %s filename threads\n"
+ " filename - MathProg model file\n"
+ " threads - number of threads\n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ n = atoi(argv[2]);
+ if (n > 50) {
+ printf("Number of threads is to high (> 50).\n");
+ exit(EXIT_FAILURE);
+ }
+ if (n <= 1) {
+ printf("Need positive number of threads\n");
+ exit(EXIT_FAILURE);
+ }
+
+ tasks = calloc(n, sizeof(struct task));
+ if (!tasks) {
+ printf("Out of memory");
+ exit(EXIT_FAILURE);
+ }
+
+ pthread_mutex_init(&mutex, NULL);
+
+ for (i = 0; i < n; ++i) {
+ tasks[i].filename = argv[1];
+ tasks[i].seed = i + 1;
+ tasks[i].pos = 0;
+ tasks[i].buf[0] = 0;
+ tasks[i].line = 0;
+ rc = pthread_create(&tasks[i].tid, NULL, run, &tasks[i]);
+ if (rc) {
+ printf("ERROR; return code from pthread_create() is %d\n", rc);
+ exit(EXIT_FAILURE);
+ }
+ }
+ for (i = 0; i < n; ++i) {
+ pthread_join(tasks[i].tid, NULL);
+ }
+
+ pthread_mutex_destroy(&mutex);
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/tls/thread.h b/examples/tls/thread.h
new file mode 100644
index 0000000..7853c36
--- /dev/null
+++ b/examples/tls/thread.h
@@ -0,0 +1,53 @@
+/* thread.h (Threading) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Author: Heinrich Schuchardt
+*
+* Copyright (C) 2000-2017 Andrew Makhorin, Department for Applied
+* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
+* reserved. E-mail: .
+*
+* GLPK is free software: you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* GLPK is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+* License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with GLPK. If not, see .
+***********************************************************************/
+
+#ifndef THREAD_H
+
+#define THREAD_H 1
+
+#ifdef HAVE_CONF_H
+#include "config.h"
+#endif // HAVE_CONF_H
+
+#ifdef __WOE__
+#include
+typedef CRITICAL_SECTION pthread_mutex_t;
+typedef DWORD pthread_t;
+//@todo The return type of routine C is "DWORD" for Windows and "void *" for Posix.
+#define pthread_create(A,B,C,D) \
+ (int)(CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&C,D,0,A)==NULL)
+#define pthread_exit(A) ExitThread(0)
+#define pthread_mutex_destroy(A) DeleteCriticalSection(A)
+#define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0)
+#define pthread_mutex_lock(A) (EnterCriticalSection(A),0)
+#define pthread_mutex_unlock(A) (LeaveCriticalSection(A),0)
+#define pthread_self() GetCurrentThreadId()
+#define pthread_join(A, B) \
+ (WaitForSingleObject(A, INFINITE),CloseHandle(A),0)
+#else
+#include
+#endif
+
+#endif // THREAD_H
--
2.1.4