368 lines
10 KiB
C++
368 lines
10 KiB
C++
|
// parallel_import.cpp
|
||
|
/*
|
||
|
The MIT License (MIT)
|
||
|
Copyright (c) 2018 HouSisong
|
||
|
|
||
|
Permission is hereby granted, free of charge, to any person
|
||
|
obtaining a copy of this software and associated documentation
|
||
|
files (the "Software"), to deal in the Software without
|
||
|
restriction, including without limitation the rights to use,
|
||
|
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
copies of the Software, and to permit persons to whom the
|
||
|
Software is furnished to do so, subject to the following
|
||
|
conditions:
|
||
|
|
||
|
The above copyright notice and this permission notice shall be
|
||
|
included in all copies of the Software.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||
|
*/
|
||
|
#include "parallel_import.h"
|
||
|
#include <assert.h>
|
||
|
|
||
|
#if (_IS_USED_PTHREAD)
|
||
|
# ifdef WIN32
|
||
|
# include "windows.h" //for Sleep
|
||
|
# //pragma comment(lib,"pthread.lib") //for static pthread lib
|
||
|
# //define PTW32_STATIC_LIB //for static pthread lib
|
||
|
# endif
|
||
|
# include <pthread.h>
|
||
|
# ifdef __ANDROID__
|
||
|
# include <sched.h> // sched_yield()
|
||
|
# endif
|
||
|
#endif
|
||
|
#if (_IS_USED_CPP11THREAD)
|
||
|
# include <thread>
|
||
|
# include <mutex>
|
||
|
# include <condition_variable>
|
||
|
#endif
|
||
|
#if (_IS_USED_WIN32THREAD)
|
||
|
# include "windows.h"
|
||
|
# ifndef UNDER_CE
|
||
|
# include "process.h"
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
#if (_IS_USED_PTHREAD)
|
||
|
#include <string.h> //for memset
|
||
|
#include <stdlib.h>
|
||
|
#include <stdexcept>
|
||
|
#include <string>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
static std::string _i2a(int ivalue){
|
||
|
const int kMaxNumCharSize =32;
|
||
|
std::string result;
|
||
|
result.resize(kMaxNumCharSize);
|
||
|
#ifdef _MSC_VER
|
||
|
int len=sprintf_s(&result[0],kMaxNumCharSize,"%d",ivalue);
|
||
|
#else
|
||
|
int len=sprintf(&result[0],"%d",ivalue);
|
||
|
#endif
|
||
|
result.resize(len);
|
||
|
return result;
|
||
|
}
|
||
|
#define _check_pthread(result,func_name) { \
|
||
|
if (result!=0) throw std::runtime_error(func_name "() return "+_i2a(result)+" error!"); }
|
||
|
|
||
|
HLocker locker_new(void){
|
||
|
pthread_mutex_t* self=new pthread_mutex_t();
|
||
|
int rt=pthread_mutex_init(self, 0);
|
||
|
if (rt!=0){
|
||
|
delete self;
|
||
|
_check_pthread(rt,"pthread_mutex_init");
|
||
|
}
|
||
|
return self;
|
||
|
}
|
||
|
void locker_delete(HLocker locker){
|
||
|
if (locker!=0){
|
||
|
pthread_mutex_t* self=(pthread_mutex_t*)locker;
|
||
|
int rt=pthread_mutex_destroy(self);
|
||
|
delete self;
|
||
|
_check_pthread(rt,"pthread_mutex_destroy");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void locker_enter(HLocker locker){
|
||
|
pthread_mutex_t* self=(pthread_mutex_t*)locker;
|
||
|
int rt=pthread_mutex_lock(self);
|
||
|
_check_pthread(rt,"pthread_mutex_lock");
|
||
|
}
|
||
|
void locker_leave(HLocker locker){
|
||
|
pthread_mutex_t* self=(pthread_mutex_t*)locker;
|
||
|
int rt=pthread_mutex_unlock(self);
|
||
|
_check_pthread(rt,"pthread_mutex_unlock");
|
||
|
}
|
||
|
|
||
|
HCondvar condvar_new(void){
|
||
|
pthread_cond_t* self=new pthread_cond_t();
|
||
|
int rt=pthread_cond_init(self,0);
|
||
|
if (rt!=0){
|
||
|
delete self;
|
||
|
_check_pthread(rt,"pthread_cond_init");
|
||
|
}
|
||
|
return self;
|
||
|
}
|
||
|
void condvar_delete(HCondvar cond){
|
||
|
if (cond){
|
||
|
pthread_cond_t* self=(pthread_cond_t*)cond;
|
||
|
int rt=pthread_cond_destroy(self);
|
||
|
delete self;
|
||
|
_check_pthread(rt,"pthread_cond_destroy");
|
||
|
}
|
||
|
}
|
||
|
void condvar_wait(HCondvar cond,TLockerBox* lockerBox){
|
||
|
pthread_cond_t* self=(pthread_cond_t*)cond;
|
||
|
int rt=pthread_cond_wait(self,(pthread_mutex_t*)(lockerBox->locker));
|
||
|
_check_pthread(rt,"pthread_cond_wait");
|
||
|
}
|
||
|
void condvar_signal(HCondvar cond){
|
||
|
pthread_cond_t* self=(pthread_cond_t*)cond;
|
||
|
int rt=pthread_cond_signal(self);
|
||
|
_check_pthread(rt,"pthread_cond_signal");
|
||
|
}
|
||
|
void condvar_broadcast(HCondvar cond){
|
||
|
pthread_cond_t* self=(pthread_cond_t*)cond;
|
||
|
int rt=pthread_cond_broadcast(self);
|
||
|
_check_pthread(rt,"pthread_cond_broadcast");
|
||
|
}
|
||
|
|
||
|
void this_thread_yield(){
|
||
|
#ifdef __APPLE__
|
||
|
pthread_yield_np();
|
||
|
#else
|
||
|
# ifdef WIN32
|
||
|
Sleep(0);
|
||
|
# else
|
||
|
# ifdef __ANDROID__
|
||
|
sched_yield();
|
||
|
# else
|
||
|
pthread_yield();
|
||
|
# endif
|
||
|
# endif
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
struct _TThreadData{
|
||
|
TThreadRunCallBackProc threadProc;
|
||
|
int threadIndex;
|
||
|
void* workData;
|
||
|
};
|
||
|
static void* _pt_threadProc(void* _pt){
|
||
|
_TThreadData* pt=(_TThreadData*)_pt;
|
||
|
pt->threadProc(pt->threadIndex,pt->workData);
|
||
|
delete pt;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void thread_parallel(int threadCount,TThreadRunCallBackProc threadProc,void* workData,
|
||
|
int isUseThisThread,int threadIndexOffset){
|
||
|
for (int i=0; i<threadCount; ++i) {
|
||
|
if ((i==threadCount-1)&&(isUseThisThread)){
|
||
|
threadProc(i+threadIndexOffset,workData);
|
||
|
}else{
|
||
|
_TThreadData* pt=new _TThreadData();
|
||
|
pt->threadIndex=i+threadIndexOffset;
|
||
|
pt->threadProc=threadProc;
|
||
|
pt->workData=workData;
|
||
|
pthread_t t; memset(&t,0,sizeof(pthread_t));
|
||
|
int rt=pthread_create(&t,0,_pt_threadProc,pt);
|
||
|
if (rt!=0){
|
||
|
delete pt;
|
||
|
_check_pthread(rt,"pthread_create");
|
||
|
}
|
||
|
rt=pthread_detach(t);
|
||
|
_check_pthread(rt,"pthread_detach");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif //_IS_USED_PTHREAD
|
||
|
|
||
|
#if (_IS_USED_CPP11THREAD)
|
||
|
HLocker locker_new(void){
|
||
|
return new std::mutex();
|
||
|
}
|
||
|
void locker_delete(HLocker locker){
|
||
|
if (locker!=0)
|
||
|
delete (std::mutex*)locker;
|
||
|
}
|
||
|
|
||
|
void locker_enter(HLocker locker){
|
||
|
std::mutex* self=(std::mutex*)locker;
|
||
|
self->lock();
|
||
|
|
||
|
}
|
||
|
void locker_leave(HLocker locker){
|
||
|
std::mutex* self=(std::mutex*)locker;
|
||
|
self->unlock();
|
||
|
}
|
||
|
|
||
|
HCondvar condvar_new(void){
|
||
|
std::condition_variable* self=new std::condition_variable();
|
||
|
return self;
|
||
|
}
|
||
|
void condvar_delete(HCondvar cond){
|
||
|
if (cond){
|
||
|
std::condition_variable* self=(std::condition_variable*)cond;
|
||
|
delete self;
|
||
|
}
|
||
|
}
|
||
|
void condvar_wait(HCondvar cond,TLockerBox* locker){
|
||
|
std::condition_variable* self=(std::condition_variable*)cond;
|
||
|
_TLockerBox_name* _locker=(_TLockerBox_name*)locker;
|
||
|
self->wait(*_locker);
|
||
|
}
|
||
|
void condvar_signal(HCondvar cond){
|
||
|
std::condition_variable* self=(std::condition_variable*)cond;
|
||
|
self->notify_one();
|
||
|
}
|
||
|
void condvar_broadcast(HCondvar cond){
|
||
|
std::condition_variable* self=(std::condition_variable*)cond;
|
||
|
self->notify_all();
|
||
|
}
|
||
|
|
||
|
void this_thread_yield(){
|
||
|
std::this_thread::yield();
|
||
|
}
|
||
|
|
||
|
|
||
|
struct _TThreadProc{
|
||
|
TThreadRunCallBackProc threadProc;
|
||
|
int threadIndex;
|
||
|
void* workData;
|
||
|
inline void operator()(){ threadProc(threadIndex,workData); }
|
||
|
};
|
||
|
void thread_parallel(int threadCount,TThreadRunCallBackProc threadProc,void* workData,
|
||
|
int isUseThisThread,int threadIndexOffset){
|
||
|
for (int i=0; i<threadCount; ++i) {
|
||
|
if ((i==threadCount-1)&&(isUseThisThread)){
|
||
|
threadProc(i+threadIndexOffset,workData);
|
||
|
}else{
|
||
|
_TThreadProc tp={threadProc,i+threadIndexOffset,workData};
|
||
|
std::thread t(tp);
|
||
|
t.detach();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif //_IS_USED_CPP11THREAD
|
||
|
|
||
|
|
||
|
#if (_IS_USED_WIN32THREAD)
|
||
|
#include <string.h> //for memset
|
||
|
#include <stdlib.h>
|
||
|
#include <stdexcept>
|
||
|
#include <string>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#define _check(value,func_name) { \
|
||
|
if (!(value)) throw std::runtime_error(func_name "() run error!"); }
|
||
|
|
||
|
|
||
|
HLocker locker_new(void){
|
||
|
CRITICAL_SECTION* self=new CRITICAL_SECTION();
|
||
|
InitializeCriticalSection(self);
|
||
|
return self;
|
||
|
}
|
||
|
void locker_delete(HLocker locker){
|
||
|
if (locker!=0){
|
||
|
CRITICAL_SECTION* self=(CRITICAL_SECTION*)locker;
|
||
|
DeleteCriticalSection(self);
|
||
|
delete self;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void locker_enter(HLocker locker){
|
||
|
CRITICAL_SECTION* self=(CRITICAL_SECTION*)locker;
|
||
|
EnterCriticalSection(self);
|
||
|
}
|
||
|
void locker_leave(HLocker locker){
|
||
|
CRITICAL_SECTION* self=(CRITICAL_SECTION*)locker;
|
||
|
LeaveCriticalSection(self);
|
||
|
}
|
||
|
|
||
|
HCondvar condvar_new(void){
|
||
|
CONDITION_VARIABLE* self=new CONDITION_VARIABLE();
|
||
|
InitializeConditionVariable(self);
|
||
|
return self;
|
||
|
}
|
||
|
void condvar_delete(HCondvar cond){
|
||
|
if (cond){
|
||
|
CONDITION_VARIABLE* self=(CONDITION_VARIABLE*)cond;
|
||
|
delete self;
|
||
|
}
|
||
|
}
|
||
|
void condvar_wait(HCondvar cond,TLockerBox* lockerBox){
|
||
|
CONDITION_VARIABLE* self=(CONDITION_VARIABLE*)cond;
|
||
|
BOOL rt=SleepConditionVariableCS(self,(CRITICAL_SECTION*)(lockerBox->locker),INFINITE);
|
||
|
_check(rt,"SleepConditionVariableCS");
|
||
|
}
|
||
|
void condvar_signal(HCondvar cond){
|
||
|
CONDITION_VARIABLE* self=(CONDITION_VARIABLE*)cond;
|
||
|
WakeConditionVariable(self);
|
||
|
}
|
||
|
void condvar_broadcast(HCondvar cond){
|
||
|
CONDITION_VARIABLE* self=(CONDITION_VARIABLE*)cond;
|
||
|
WakeAllConditionVariable(self);
|
||
|
}
|
||
|
|
||
|
void this_thread_yield(){
|
||
|
Sleep(0);
|
||
|
}
|
||
|
|
||
|
struct _TThreadData{
|
||
|
TThreadRunCallBackProc threadProc;
|
||
|
int threadIndex;
|
||
|
void* workData;
|
||
|
};
|
||
|
|
||
|
#ifdef UNDER_CE
|
||
|
static DWORD WINAPI _win_threadProc(void* _pt){
|
||
|
#else
|
||
|
static unsigned int WINAPI _win_threadProc(void* _pt){
|
||
|
#endif
|
||
|
_TThreadData* pt=(_TThreadData*)_pt;
|
||
|
pt->threadProc(pt->threadIndex,pt->workData);
|
||
|
delete pt;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
template <class TProc>
|
||
|
inline static HANDLE _thread_create(TProc func,void* param){
|
||
|
#ifdef UNDER_CE
|
||
|
DWORD threadId;
|
||
|
return CreateThread(0,0,func,param,0,&threadId);
|
||
|
#else
|
||
|
unsigned threadId;
|
||
|
return (HANDLE)_beginthreadex(0,0,func,param,0,&threadId);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void thread_parallel(int threadCount,TThreadRunCallBackProc threadProc,void* workData,
|
||
|
int isUseThisThread,int threadIndexOffset){
|
||
|
for (int i=0; i<threadCount; ++i) {
|
||
|
if ((i==threadCount-1)&&(isUseThisThread)){
|
||
|
threadProc(i+threadIndexOffset,workData);
|
||
|
}else{
|
||
|
_TThreadData* pt=new _TThreadData();
|
||
|
pt->threadIndex=i+threadIndexOffset;
|
||
|
pt->threadProc=threadProc;
|
||
|
pt->workData=workData;
|
||
|
HANDLE rt=_thread_create(_win_threadProc,pt);
|
||
|
if (rt==0){
|
||
|
delete pt;
|
||
|
_check(rt!=0,"_thread_create");
|
||
|
} else {
|
||
|
CloseHandle(rt);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif //_IS_USED_WIN32THREAD
|