removing trailing whitespaces Compilation error on Mac fix & warning on android Warnings fixed on iOspull/4076/head
parent
96c3f16a90
commit
bf5393ae58
5 changed files with 628 additions and 0 deletions
@ -0,0 +1,592 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp" |
||||
|
||||
#if defined HAVE_PTHREADS && HAVE_PTHREADS |
||||
|
||||
#include <algorithm> |
||||
#include <pthread.h> |
||||
|
||||
namespace cv |
||||
{ |
||||
|
||||
class ThreadManager; |
||||
|
||||
enum ForThreadState |
||||
{ |
||||
eFTNotStarted = 0, |
||||
eFTStarted = 1, |
||||
eFTToStop = 2, |
||||
eFTStoped = 3 |
||||
}; |
||||
|
||||
enum ThreadManagerPoolState |
||||
{ |
||||
eTMNotInited = 0, |
||||
eTMFailedToInit = 1, |
||||
eTMInited = 2, |
||||
eTMSingleThreaded = 3 |
||||
}; |
||||
|
||||
struct work_load |
||||
{ |
||||
work_load() |
||||
{ |
||||
clear(); |
||||
} |
||||
|
||||
work_load(const cv::Range& range, const cv::ParallelLoopBody& body, int nstripes) |
||||
{ |
||||
set(range, body, nstripes); |
||||
} |
||||
|
||||
void set(const cv::Range& range, const cv::ParallelLoopBody& body, int nstripes) |
||||
{ |
||||
m_body = &body; |
||||
m_range = ⦥ |
||||
m_nstripes = nstripes; |
||||
m_blocks_count = ((m_range->end - m_range->start - 1)/m_nstripes) + 1; |
||||
} |
||||
|
||||
const cv::ParallelLoopBody* m_body; |
||||
const cv::Range* m_range; |
||||
int m_nstripes; |
||||
unsigned int m_blocks_count; |
||||
|
||||
void clear() |
||||
{ |
||||
m_body = 0; |
||||
m_range = 0; |
||||
m_nstripes = 0; |
||||
m_blocks_count = 0; |
||||
} |
||||
}; |
||||
|
||||
class ForThread |
||||
{ |
||||
public: |
||||
|
||||
ForThread(): m_task_start(false), m_parent(0), m_state(eFTNotStarted), m_id(0) |
||||
{ |
||||
} |
||||
|
||||
//called from manager thread
|
||||
bool init(size_t id, ThreadManager* parent); |
||||
|
||||
//called from manager thread
|
||||
void run(); |
||||
|
||||
//called from manager thread
|
||||
void stop(); |
||||
|
||||
~ForThread(); |
||||
|
||||
private: |
||||
|
||||
//called from worker thread
|
||||
static void* thread_loop_wrapper(void* thread_object); |
||||
|
||||
//called from worker thread
|
||||
void execute(); |
||||
|
||||
//called from worker thread
|
||||
void thread_body(); |
||||
|
||||
pthread_t m_posix_thread; |
||||
pthread_mutex_t m_thread_mutex; |
||||
pthread_cond_t m_cond_thread_task; |
||||
bool m_task_start; |
||||
|
||||
ThreadManager* m_parent; |
||||
ForThreadState m_state; |
||||
size_t m_id; |
||||
}; |
||||
|
||||
class ThreadManager |
||||
{ |
||||
public: |
||||
friend class ForThread; |
||||
|
||||
static ThreadManager& instance() |
||||
{ |
||||
if(!m_instance.ptr) |
||||
{ |
||||
pthread_mutex_lock(&m_manager_access_mutex); |
||||
|
||||
if(!m_instance.ptr) |
||||
{ |
||||
m_instance.ptr = new ThreadManager(); |
||||
} |
||||
|
||||
pthread_mutex_unlock(&m_manager_access_mutex); |
||||
} |
||||
|
||||
return *m_instance.ptr; |
||||
} |
||||
|
||||
|
||||
static void stop() |
||||
{ |
||||
ThreadManager& manager = instance(); |
||||
|
||||
if(manager.m_pool_state == eTMInited) |
||||
{ |
||||
for(size_t i = 0; i < manager.m_num_threads; ++i) |
||||
{ |
||||
manager.m_threads[i].stop(); |
||||
} |
||||
} |
||||
|
||||
manager.m_pool_state = eTMNotInited; |
||||
} |
||||
|
||||
void run(const cv::Range& range, const cv::ParallelLoopBody& body, double nstripes); |
||||
|
||||
size_t getNumOfThreads(); |
||||
|
||||
void setNumOfThreads(size_t n); |
||||
|
||||
private: |
||||
|
||||
struct ptr_holder |
||||
{ |
||||
ThreadManager* ptr; |
||||
|
||||
ptr_holder(): ptr(NULL) { } |
||||
|
||||
~ptr_holder() |
||||
{ |
||||
if(ptr) |
||||
{ |
||||
delete ptr; |
||||
} |
||||
} |
||||
}; |
||||
|
||||
ThreadManager(); |
||||
|
||||
~ThreadManager(); |
||||
|
||||
void wait_complete(); |
||||
|
||||
void notify_complete(); |
||||
|
||||
bool initPool(); |
||||
|
||||
size_t defaultNumberOfThreads(); |
||||
|
||||
std::vector<ForThread> m_threads; |
||||
size_t m_num_threads; |
||||
|
||||
pthread_mutex_t m_manager_task_mutex; |
||||
pthread_cond_t m_cond_thread_task_complete; |
||||
bool m_task_complete; |
||||
|
||||
unsigned int m_task_position; |
||||
unsigned int m_num_of_completed_tasks; |
||||
|
||||
static pthread_mutex_t m_manager_access_mutex; |
||||
static ptr_holder m_instance; |
||||
|
||||
static const char m_env_name[]; |
||||
static const unsigned int m_default_number_of_threads; |
||||
|
||||
work_load m_work_load; |
||||
|
||||
struct work_thread_t |
||||
{ |
||||
work_thread_t(): value(false) { } |
||||
bool value; |
||||
}; |
||||
|
||||
cv::TLSData<work_thread_t> m_is_work_thread; |
||||
|
||||
ThreadManagerPoolState m_pool_state; |
||||
}; |
||||
|
||||
#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP |
||||
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER |
||||
#endif |
||||
|
||||
pthread_mutex_t ThreadManager::m_manager_access_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; |
||||
|
||||
ThreadManager::ptr_holder ThreadManager::m_instance; |
||||
const char ThreadManager::m_env_name[] = "OPENCV_FOR_THREADS_NUM"; |
||||
const unsigned int ThreadManager::m_default_number_of_threads = 8; |
||||
|
||||
ForThread::~ForThread() |
||||
{ |
||||
if(m_state == eFTStarted) |
||||
{ |
||||
stop(); |
||||
|
||||
pthread_mutex_destroy(&m_thread_mutex); |
||||
|
||||
pthread_cond_destroy(&m_cond_thread_task); |
||||
} |
||||
} |
||||
|
||||
bool ForThread::init(size_t id, ThreadManager* parent) |
||||
{ |
||||
m_id = id; |
||||
|
||||
m_parent = parent; |
||||
|
||||
int res = 0; |
||||
|
||||
res |= pthread_mutex_init(&m_thread_mutex, NULL); |
||||
|
||||
res |= pthread_cond_init(&m_cond_thread_task, NULL); |
||||
|
||||
if(!res) |
||||
{ |
||||
res = pthread_create(&m_posix_thread, NULL, thread_loop_wrapper, (void*)this); |
||||
} |
||||
|
||||
|
||||
return res == 0; |
||||
} |
||||
|
||||
void ForThread::stop() |
||||
{ |
||||
if(m_state == eFTStarted) |
||||
{ |
||||
m_state = eFTToStop; |
||||
|
||||
run(); |
||||
|
||||
pthread_join(m_posix_thread, NULL); |
||||
} |
||||
|
||||
m_state = eFTStoped; |
||||
} |
||||
|
||||
void ForThread::run() |
||||
{ |
||||
pthread_mutex_lock(&m_thread_mutex); |
||||
|
||||
m_task_start = true; |
||||
|
||||
pthread_cond_signal(&m_cond_thread_task); |
||||
|
||||
pthread_mutex_unlock(&m_thread_mutex); |
||||
} |
||||
|
||||
void* ForThread::thread_loop_wrapper(void* thread_object) |
||||
{ |
||||
((ForThread*)thread_object)->thread_body(); |
||||
return 0; |
||||
} |
||||
|
||||
void ForThread::execute() |
||||
{ |
||||
unsigned int m_current_pos = CV_XADD(&m_parent->m_task_position, 1); |
||||
|
||||
work_load& load = m_parent->m_work_load; |
||||
|
||||
while(m_current_pos < load.m_blocks_count) |
||||
{ |
||||
int start = load.m_range->start + m_current_pos*load.m_nstripes; |
||||
int end = std::min(start + load.m_nstripes, load.m_range->end); |
||||
|
||||
load.m_body->operator()(cv::Range(start, end)); |
||||
|
||||
m_current_pos = CV_XADD(&m_parent->m_task_position, 1); |
||||
} |
||||
} |
||||
|
||||
void ForThread::thread_body() |
||||
{ |
||||
m_parent->m_is_work_thread.get()->value = true; |
||||
|
||||
pthread_mutex_lock(&m_thread_mutex); |
||||
|
||||
m_state = eFTStarted; |
||||
|
||||
while(m_state == eFTStarted) |
||||
{ |
||||
//to handle spurious wakeups
|
||||
while( !m_task_start && m_state != eFTToStop ) |
||||
pthread_cond_wait(&m_cond_thread_task, &m_thread_mutex); |
||||
|
||||
if(m_state == eFTStarted) |
||||
{ |
||||
execute(); |
||||
|
||||
m_task_start = false; |
||||
|
||||
m_parent->notify_complete(); |
||||
} |
||||
} |
||||
|
||||
pthread_mutex_unlock(&m_thread_mutex); |
||||
} |
||||
|
||||
ThreadManager::ThreadManager(): m_num_threads(0), m_task_complete(false), m_num_of_completed_tasks(0), m_pool_state(eTMNotInited) |
||||
{ |
||||
int res = 0; |
||||
|
||||
res |= pthread_mutex_init(&m_manager_task_mutex, NULL); |
||||
|
||||
res |= pthread_cond_init(&m_cond_thread_task_complete, NULL); |
||||
|
||||
if(!res) |
||||
{ |
||||
setNumOfThreads(defaultNumberOfThreads()); |
||||
|
||||
m_task_position = 0; |
||||
} |
||||
else |
||||
{ |
||||
m_num_threads = 1; |
||||
m_pool_state = eTMFailedToInit; |
||||
m_task_position = 0; |
||||
|
||||
//print error;
|
||||
} |
||||
} |
||||
|
||||
ThreadManager::~ThreadManager() |
||||
{ |
||||
stop(); |
||||
|
||||
pthread_mutex_destroy(&m_manager_task_mutex); |
||||
|
||||
pthread_cond_destroy(&m_cond_thread_task_complete); |
||||
|
||||
pthread_mutex_destroy(&m_manager_access_mutex); |
||||
} |
||||
|
||||
void ThreadManager::run(const cv::Range& range, const cv::ParallelLoopBody& body, double nstripes) |
||||
{ |
||||
bool is_work_thread; |
||||
|
||||
is_work_thread = m_is_work_thread.get()->value; |
||||
|
||||
if( (getNumOfThreads() > 1) && !is_work_thread && (range.end - range.start > 1) ) |
||||
{ |
||||
int res = pthread_mutex_trylock(&m_manager_access_mutex); |
||||
|
||||
if(!res) |
||||
{ |
||||
if(initPool()) |
||||
{ |
||||
double min_stripes = double(range.end - range.start)/(4*m_threads.size()); |
||||
|
||||
nstripes = std::max(nstripes, min_stripes); |
||||
|
||||
pthread_mutex_lock(&m_manager_task_mutex); |
||||
|
||||
m_num_of_completed_tasks = 0; |
||||
|
||||
m_task_position = 0; |
||||
|
||||
m_task_complete = false; |
||||
|
||||
m_work_load.set(range, body, std::ceil(nstripes)); |
||||
|
||||
for(size_t i = 0; i < m_threads.size(); ++i) |
||||
{ |
||||
m_threads[i].run(); |
||||
} |
||||
|
||||
wait_complete(); |
||||
} |
||||
else |
||||
{ |
||||
//print error
|
||||
body(range); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
body(range); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
body(range); |
||||
} |
||||
} |
||||
|
||||
void ThreadManager::wait_complete() |
||||
{ |
||||
//to handle spurious wakeups
|
||||
while(!m_task_complete) |
||||
pthread_cond_wait(&m_cond_thread_task_complete, &m_manager_task_mutex); |
||||
|
||||
pthread_mutex_unlock(&m_manager_task_mutex); |
||||
|
||||
pthread_mutex_unlock(&m_manager_access_mutex); |
||||
} |
||||
|
||||
void ThreadManager::notify_complete() |
||||
{ |
||||
|
||||
unsigned int comp = CV_XADD(&m_num_of_completed_tasks, 1); |
||||
|
||||
if(comp == (m_num_threads - 1)) |
||||
{ |
||||
pthread_mutex_lock(&m_manager_task_mutex); |
||||
|
||||
m_task_complete = true; |
||||
|
||||
pthread_cond_signal(&m_cond_thread_task_complete); |
||||
|
||||
pthread_mutex_unlock(&m_manager_task_mutex); |
||||
} |
||||
} |
||||
|
||||
bool ThreadManager::initPool() |
||||
{ |
||||
if(m_pool_state != eTMNotInited || m_num_threads == 1) |
||||
return true; |
||||
|
||||
m_threads.resize(m_num_threads); |
||||
|
||||
bool res = true; |
||||
|
||||
for(size_t i = 0; i < m_threads.size(); ++i) |
||||
{ |
||||
res |= m_threads[i].init(i, this); |
||||
} |
||||
|
||||
if(res) |
||||
{ |
||||
m_pool_state = eTMInited; |
||||
} |
||||
else |
||||
{ |
||||
//TODO: join threads?
|
||||
m_pool_state = eTMFailedToInit; |
||||
} |
||||
|
||||
return res; |
||||
} |
||||
|
||||
size_t ThreadManager::getNumOfThreads() |
||||
{ |
||||
return m_num_threads; |
||||
} |
||||
|
||||
void ThreadManager::setNumOfThreads(size_t n) |
||||
{ |
||||
int res = pthread_mutex_lock(&m_manager_access_mutex); |
||||
|
||||
if(!res) |
||||
{ |
||||
if(n == 0) |
||||
{ |
||||
n = defaultNumberOfThreads(); |
||||
} |
||||
|
||||
if(n != m_num_threads && m_pool_state != eTMFailedToInit) |
||||
{ |
||||
if(m_pool_state == eTMInited) |
||||
{ |
||||
stop(); |
||||
m_threads.clear(); |
||||
} |
||||
|
||||
m_num_threads = n; |
||||
|
||||
if(m_num_threads == 1) |
||||
{ |
||||
m_pool_state = eTMSingleThreaded; |
||||
} |
||||
else |
||||
{ |
||||
m_pool_state = eTMNotInited; |
||||
} |
||||
} |
||||
|
||||
pthread_mutex_unlock(&m_manager_access_mutex); |
||||
} |
||||
} |
||||
|
||||
size_t ThreadManager::defaultNumberOfThreads() |
||||
{ |
||||
unsigned int result = m_default_number_of_threads; |
||||
|
||||
char * env = getenv(m_env_name); |
||||
|
||||
if(env != NULL) |
||||
{ |
||||
sscanf(env, "%u", &result); |
||||
|
||||
result = std::max(1u, result); |
||||
//do we need upper limit of threads number?
|
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
void parallel_for_pthreads(const cv::Range& range, const cv::ParallelLoopBody& body, double nstripes); |
||||
size_t parallel_pthreads_get_threads_num(); |
||||
void parallel_pthreads_set_threads_num(int num); |
||||
|
||||
size_t parallel_pthreads_get_threads_num() |
||||
{ |
||||
return ThreadManager::instance().getNumOfThreads(); |
||||
} |
||||
|
||||
void parallel_pthreads_set_threads_num(int num) |
||||
{ |
||||
if(num < 0) |
||||
{ |
||||
ThreadManager::instance().setNumOfThreads(0); |
||||
} |
||||
else |
||||
{ |
||||
ThreadManager::instance().setNumOfThreads(size_t(num)); |
||||
} |
||||
} |
||||
|
||||
void parallel_for_pthreads(const cv::Range& range, const cv::ParallelLoopBody& body, double nstripes) |
||||
{ |
||||
ThreadManager::instance().run(range, body, nstripes); |
||||
} |
||||
|
||||
} |
||||
|
||||
#endif |
Loading…
Reference in new issue