thread.cpp

Go to the documentation of this file.
00001 /*
00002  * File Name: thread.cpp
00003  */
00004 
00005 /*
00006  * This file is part of uds-plugin-common.
00007  *
00008  * uds-plugin-common is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * uds-plugin-common is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /**
00023  * Copyright (C) 2008 iRex Technologies B.V.
00024  * All rights reserved.
00025  */
00026 
00027 #include "thread.h"
00028 
00029 namespace common
00030 {
00031 
00032 Task::Task()
00033 {
00034     aborted = false;
00035 }
00036 
00037 Task::~Task()
00038 {
00039 }
00040 
00041 void Task::send_abort_request()
00042 {
00043     aborted = true;
00044 }
00045 
00046 Thread::Thread()
00047 : thread(NULL),
00048   thread_cmd(CMD_NONE),
00049   running_task(0)
00050 {
00051     queue_mutex = g_mutex_new();
00052     queue_cond  = g_cond_new();
00053 }
00054 
00055 Thread::~Thread()
00056 {
00057     g_mutex_free(queue_mutex);
00058     g_cond_free(queue_cond);
00059 }
00060 
00061 gpointer Thread::thread_func(gpointer args)
00062 {
00063     Thread* thiz = reinterpret_cast<Thread *>(args);
00064     return thiz->non_static_thread_func();
00065 }
00066 
00067 // Worker thread
00068 gpointer Thread::non_static_thread_func()
00069 {
00070     while (true)
00071     {
00072         g_mutex_lock(queue_mutex);
00073         while (task_queue.empty())
00074         {
00075             if (thread_cmd != CMD_NONE)
00076             {
00077                 g_mutex_unlock(queue_mutex);
00078                 goto CleanUp;
00079             }
00080 
00081             g_cond_wait(queue_cond, queue_mutex);
00082         }
00083 
00084         if (thread_cmd == CMD_TERMINATE)
00085         {
00086             g_mutex_unlock(queue_mutex);
00087             goto CleanUp;
00088         }
00089 
00090         // Get task from task queue
00091         Task *task = task_queue.front();
00092         task_queue.pop_front();
00093 
00094         g_mutex_unlock(queue_mutex);
00095 
00096         // About executing task, update running_task variable.
00097         running_task = task;
00098         task->execute();
00099         // Task execution done, update running_task variable.
00100         running_task = 0;
00101 
00102         // Release task object
00103         delete task;
00104     }
00105 
00106 CleanUp:
00107     clear_all();
00108     return 0;
00109 }
00110 
00111 void Thread::clear_all()
00112 {
00113     g_mutex_lock(queue_mutex);
00114 
00115     std::list<Task*>::iterator it = task_queue.begin();
00116     while (it != task_queue.end())
00117     {
00118         delete *it;
00119         it = task_queue.erase(it);
00120     }
00121 
00122     g_mutex_unlock(queue_mutex);
00123 }
00124 
00125 bool Thread::start()
00126 {
00127     if (thread != NULL)
00128     {
00129         // The thread has been started.
00130         return false;
00131     }
00132 
00133     thread = g_thread_create(thread_func, this, TRUE, NULL);
00134     return thread != NULL;
00135 }
00136 
00137 void Thread::stop(bool cancel_all_tasks)
00138 {
00139     if (thread == NULL)
00140     {
00141         return;
00142     }
00143 
00144     thread_cmd = cancel_all_tasks ? CMD_TERMINATE : CMD_STOP;
00145 
00146     if (running_task != 0)
00147     {
00148         if (cancel_all_tasks)
00149         {
00150             running_task->send_abort_request();
00151         }
00152     }
00153     else
00154     {
00155         // Woker thread is waiting for a task, wake it up.
00156         g_cond_signal(queue_cond);
00157     }
00158 
00159     // Wait for worker thread to die.
00160     g_thread_join(thread);
00161 
00162     // Set the thread to be NULL
00163     thread = NULL;
00164 }
00165 
00166 bool Thread::append_task(Task* new_task)
00167 {
00168     if (thread_cmd == CMD_NONE)
00169     {
00170         // Append task to the end of the task queue.
00171         g_mutex_lock(queue_mutex);
00172         task_queue.push_back(new_task);
00173         g_mutex_unlock(queue_mutex);
00174 
00175         // Tells the worker thread that a new task is available.
00176         g_cond_signal(queue_cond);
00177         return true;
00178     }
00179     else
00180     {
00181         delete new_task;
00182         return false;
00183     }
00184 }
00185 
00186 bool Thread::prepend_task(Task* new_task, bool abort_current)
00187 {
00188     if (thread_cmd == CMD_NONE)
00189     {
00190         // Insert task to the beginning of the task queue.
00191         g_mutex_lock(queue_mutex);
00192         task_queue.push_front(new_task);
00193 
00194         if (abort_current)
00195         {
00196             abort_current_task();
00197         }
00198 
00199         g_mutex_unlock(queue_mutex);
00200 
00201         // Tells the worker thread that a new task is available.
00202         g_cond_signal(queue_cond);
00203 
00204         return true;
00205     }
00206     else
00207     {
00208         delete new_task;
00209         return false;
00210     }
00211 }
00212 
00213 bool Thread::abort_current_task()
00214 {
00215     if (running_task != 0)
00216     {
00217         // Worker thread is executing a task, just abort it.
00218         running_task->send_abort_request();
00219         return true;
00220     }
00221     else
00222     {
00223         // Woker thread is waiting for a task
00224         return false;
00225     }
00226 }
00227 
00228 }
Generated by  doxygen 1.6.2-20100208