1 /***************************************************************************
2 * Copyright (C) 2008 by Michael Andreen *
3 * andreen@student.chalmers.se *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *
19 ***************************************************************************/
21 #include "threadgenesorter.h"
22 #include "sortaction.h"
24 #include "genealgorithms.h"
33 * Handles locking and unlocking of mutexes.
35 * RAII style class for mutex acquisition.
41 Mutex(pthread_mutex_t* m){
43 pthread_mutex_lock(_m);
47 pthread_mutex_unlock(_m);
56 struct ExecutionStuff {
57 ExecutionStuff(ThreadGeneSorter* so, const GeneOrder& go): _sorter(so)
59 ThreadGeneSorter* _sorter;
64 ThreadGeneSorter::ThreadGeneSorter(const Model& m, int threads) : _model(m){
66 pthread_mutex_init(&_queuelock, NULL);
67 pthread_mutex_init(&_solutionslock, NULL);
68 pthread_cond_init(&_addedSolution,NULL);
69 pthread_cond_init(&_addedTask,NULL);
70 pthread_cond_init(&_waiting,NULL);
73 void ThreadGeneSorter::join(){
74 pthread_join(_tid,NULL);
77 void ThreadGeneSorter::stop(){
80 pthread_cond_signal(&_waiting);
83 size_t ThreadGeneSorter::size(){
84 Mutex m(&_solutionslock);
85 return _solutions.size();
88 bool ThreadGeneSorter::running(){
92 double ThreadGeneSorter::wait(time_t time, size_t solutions){
95 gettimeofday(&now, NULL);
97 timeout.tv_sec = now.tv_sec + time;
102 Mutex m(&_solutionslock);
103 size_t n = _solutions.size();
105 while (!_done && err != ETIMEDOUT
106 && _solutions.size() - n < solutions){
107 err = pthread_cond_timedwait(&_addedSolution,&_solutionslock
110 if (_solutions.size() == 0)
112 return _solutions.top().first;
115 ThreadGeneSorter::SolutionsQueue ThreadGeneSorter::solutions(){
116 //TODO: thread safety..
120 void ThreadGeneSorter::start(const GeneOrder& go){
121 pthread_attr_t tattr;
122 pthread_attr_init(&tattr);
123 pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
124 ExecutionStuff* es = new ExecutionStuff(this,go);
125 pthread_create(&_tid, &tattr, t_sorter, es);
128 void ThreadGeneSorter::sorter(const GeneOrder& go){
129 _queue.push(SortUnit(0.0,go,ActionList()));
130 pthread_attr_t tattr;
131 pthread_attr_init(&tattr);
132 pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
134 _queue = SortQueue();
135 _solutions = SolutionsQueue();
137 queue<pthread_t> threads;
139 _queue.push(SortUnit(0.0,go,ActionList()));
141 int workers = _workers;
146 pthread_create(&tid, &tattr, t_worker, this);
149 Mutex m(&_queuelock);
150 while(_workers != 0 && !_done){
151 pthread_cond_wait(&_waiting,&_queuelock);
157 pthread_cond_broadcast(&_addedTask);
158 while(threads.size() > 0){
159 pthread_join(threads.front(),NULL);
162 pthread_exit((void*)0);
165 void ThreadGeneSorter::worker(){
168 Mutex m(&_queuelock);
170 while (_queue.size() == 0 && !_done){
172 pthread_cond_signal(&_waiting);
173 pthread_cond_wait(&_addedTask,&_queuelock);
179 SortUnit su = _queue.top();
183 size_t dist = inversionDistance(su._go);
185 Mutex m(&_solutionslock);
186 _solutions.push(pair<double,ActionList>(su._score,su._al));
187 pthread_cond_broadcast(&_addedSolution);
191 ActionList act = safeActions(su._go);
193 set<SortAction> safe(act.begin(), act.end());
194 for (set<SortAction>::iterator sa = safe.begin(); sa != safe.end(); ++sa){
195 GeneOrder go(su._go);
196 ActionList al(su._al);
199 double score = su._score + _model.score(*sa,su._go);
200 Mutex m(&_queuelock);
201 _queue.push(SortUnit(score,go,al));
203 pthread_cond_broadcast(&_addedTask);
207 }catch(const bad_alloc& e){
212 void* t_sorter(void* arg){
213 ExecutionStuff* es = static_cast<ExecutionStuff*>(arg);
214 es->_sorter->sorter(es->_go);
216 pthread_exit((void*)0);
219 void* t_worker(void* arg){
220 ThreadGeneSorter* sorter = static_cast<ThreadGeneSorter*>(arg);
222 pthread_exit((void*)0);