Posix Thread 怎么实现挂起和恢复阿?

程英杭 2009-09-26 07:31:05
我现在在封装线程的类,我希望我的类有如下功能:
class Thread
{
Thread(StartFunc);//初始化线程类
Start();//启动线程
Join();//等待线程结束
Cancel();//取消线程
Suspend();//挂起线程
Resume();//恢复挂起的线程
Abort();//退出线程
}

结果在实现的时候,由于像Cancel,Suspend, Resume很难实现。
主要是因为 这个线程类执行的不是自己写的函数,那么在该函数中就没有办法监视一些条件变量。所以感觉挂起和恢复根本实现不了,有没有哪位朋友实现了类似功能,或者能否提供一个合理的方法,让我尝试下。注:不能使用pthread_kill()这个函数。
我最后希望达到的效果就是
void Test()
{}
Thread* t = new Thread(Test);
t-Start();

t->Suspend();//这样就挂起线程
t->Resume();//这样就恢复挂起线程
t->Cancel();//就能取消正在执行的操作

t->Join();
...全文
298 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
daidodo 2009-09-29
  • 打赏
  • 举报
回复
根据我的理解,lz实际上是想控制线程的优先级,可以man一下pthread_attr_getschedpolicy等函数。
同时建议,使用suspend和resume的方式来实现,绝对是很不好的方式。
程英杭 2009-09-29
  • 打赏
  • 举报
回复
使用Resume和Suspend这种方式,主要是因为一般这个是通过条件变量和互斥锁来实现,所以用得不小心是会引起一些不必要的麻烦,所以我打算尽可能的把这些封装在类中,由我自己控制,不要程序员控制。
像我上面的做法,如果让程序员通过注册Suspend的入口点,那么就能实现挂起和恢复的功能了。但这样的麻烦在于程序员必须调用这个函数,而且,我上面也提到了,不能做到在一些没有循环体的函数中设置入口点。也就达不到我最理想的要求。
程英杭 2009-09-29
  • 打赏
  • 举报
回复
这个和优先级没有关系,其实我主要想实现类似OS400这样的操作系统中的作业控制功能,即作业在执行过程中可以人为的控制让某个活动作业先Hold住,然后方便做些脚本或检查下数据是否正常,再Release作业,让作业继续下去。
程英杭 2009-09-27
  • 打赏
  • 举报
回复
我主要是不想编写线程函数的程序员 考虑怎么和主线程之间通信以实现Suspend和Resume,而是 希望这些由我自己完成,这样编写线程函数的程序员 只需要实现自己的功能就可以了,如果主线程有需要挂起或恢复线程的话 由他自己完成,其实我想达到的目的就是做到和.net的Thread 类一样,现在就差这两个函数不能实现,主要也就是因为没有在线程函数中加入和主线程通讯的条件变量或者锁,因为 编写线程函数的 一般都是考虑业务逻辑,如果要让他考虑线程相关的,那么难度就增加了,
daidodo 2009-09-27
  • 打赏
  • 举报
回复
根据lz使用多线程的方式,其实可以很自然的实现Cancel,Suspend, Resume等操作。

一般情况下,线程有2中运行方式:定时循环执行,作为生产者和/或消费者执行。

如果是定时执行,无所谓挂起和恢复,用sleep等函数就行了。

如果是生产者和/或消费者,必然会“等待”队列数据,这时主要用条件变量实现Suspend和Resume,即队列空就Suspend,队列有数据时Resume。

至于Cancel,我的理解是线程主动退出,用在可自动伸缩的线程池里。这时一般需要另一个调度线程,根据队列的长度,制定伸缩策略,而工作线程则根据策略自动改变自己的行为(退出线程或等待队列)。

下面是以前写的一个可伸缩的线程池的部分代码,仅供参考:
template<class Que>
class CThreadManager
{
typedef CLockInt<int,CSpinLock> __ThreadCount;
typedef CActive<__ThreadCount> __Active;
typedef CSpinLock __Lock;
typedef CGuard<__Lock> __Guard;
protected:
typedef Que __Queue;
typedef typename __Queue::value_type __Job;
private:
static const int SCHEDULE_INTERVAL_DEFAULT = 1; //s, 默认调度间隔
static const int THREAD_COUNT_MIN_DEFAULT = 2; //默认最少线程数
static const int THREAD_COUNT_MAX_DEFAULT = 32; //默认最多线程数
//worker thread
static void * threadProc(void * arg){
assert(arg);
CThreadManager & self = *reinterpret_cast<CThreadManager *>(arg);
for(__Job job;self.querySurvive();){
self.inputQue_.Pop(job);
__Active act(self.activeCount_);
self.doIt(job);
}
--self.threadCount_;
return 0;
}
//schedule thread
static void * threadSchedule(void * arg){
assert(arg);
CThreadManager & self = *reinterpret_cast<CThreadManager *>(arg);
for(;;){
sleep(self.interval_);
int active = self.activeCount_;
int count = self.threadCount_;
active = self.adjustThreadCount(active << 1); //Expect
if(active > count) //need more threads
self.addThreads(active - count);
else{ //have waste threads
count -= active; //Waste
if(count >= 5 && count >= (active >> 1))
self.deleteThread(count);
}
}
return 0;
}
public:
CThreadManager(__Queue & input_que,size_t stack_sz = 16 << 10)
: inputQue_(input_que)
, stackSz_(stack_sz)
, schedule_(0)
, interval_(SCHEDULE_INTERVAL_DEFAULT)
, deleteCount_(0)
, threadCountMax_(THREAD_COUNT_MAX_DEFAULT)
, threadCountMin_(THREAD_COUNT_MIN_DEFAULT)
{}
virtual ~CThreadManager(){}
//name为服务线程的名字
//thread_count为初始线程数,如果超过[threadCountMin_,threadCountMax_]的范围,则采用默认值
//return +n(启动的线程数),-1(错误)
virtual int StartThreads(__DZ_STRING name,int thread_count = 0){
LOCAL_LOGGER(logger,"CThreadManager::StartThreads");
if(Started())
return -1; //重复启动
name_ = name;
if(name_.empty())
name_.push_back(' ');
//start schedule thread
if(pthread_create(&schedule_,0,threadSchedule,this)){
FATAL_COUT(name_<<"'s schedule thread start failed"<<Tools::ErrorMsg(errno));
}else{
INFO(name_<<"'s schedule thread("<<schedule_<<") starts");
}
//start worker threads
return addThreads(adjustThreadCount(thread_count));
}
virtual void WaitAll(){
pthread_join(schedule_,0);
}
bool Started() const{return !name_.empty();}
int ThreadCount() const{return threadCount_;}
int ActiveCount() const{return activeCount_;}
//设置调度线程的处理间隔时间(秒)
void ScheduleInterval(int timeS){interval_ = timeS;}
void ThreadCountMax(int thread_max){
if(thread_max >= threadCountMin_)
threadCountMax_ = thread_max;
}
void ThreadCountMin(int thread_min){
if(thread_min <= threadCountMax_ && thread_min >= THREAD_COUNT_MIN_DEFAULT)
threadCountMin_ = thread_min;
}
int ScheduleInterval() const{return interval_;}
int ThreadCountMax() const{return threadCountMax_;}
int ThreadCountMin() const{return threadCountMin_;}
protected:
virtual void doIt(__Job &) = 0;
private:
//return启动的线程数
int addThreads(int thread_count){
assert(thread_count > 0);
LOCAL_LOGGER(logger,"CThreadManager::addThreads_aux");
//set stack size
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr,stackSz_);
pthread_t th = 0;
int ret = 0;
for(int i = 0;i < thread_count;++i){
if(pthread_create(&th,&attr,threadProc,this)){
ERROR_COUT("pthread_create error"<<Tools::ErrorMsg(errno));
}else{
pthread_detach(th);
INFO(name_<<"("<<th<<") thread starts");
++ret;
}
}
pthread_attr_destroy(&attr);
threadCount_ += ret;
return ret;
}
void deleteThread(int thread_count){
assert(thread_count > 0);
__Guard g(deleteLock_);
deleteCount_ = thread_count;
}
bool querySurvive(){
__Guard g(deleteLock_);
assert(deleteCount_ >= 0);
if(!deleteCount_)
return true;
--deleteCount_;
return false;
}
int adjustThreadCount(int thread_count) const{
const int t_min = threadCountMin_;
const int t_max = threadCountMax_;
if(thread_count < t_min)
return t_min;
if(thread_count > t_max)
return t_max;
return thread_count;
}
//fields:
__Queue & inputQue_;
const size_t stackSz_;
__DZ_STRING name_;
//schedule thread
pthread_t schedule_;
int interval_; //s, 调度频率
//用于删除多余线程
CSpinLock deleteLock_;
int deleteCount_;
//thread counts
__ThreadCount threadCount_;
__ThreadCount activeCount_;
volatile int threadCountMax_;
volatile int threadCountMin_;
};


对于的“业务逻辑”与“底层逻辑”的分离,其实所有的线程池实现都是为了这个目的。
上面的代码里,业务逻辑全部在
virtual void doIt(__Job &) = 0;

函数里,这是唯一需要子类实现的纯虚函数。
程英杭 2009-09-27
  • 打赏
  • 举报
回复
DreamFreeLancer 我目前的实现就和你说的是一样的,但确实不能做到完全透明. 我总感觉这样让程序员使用很麻烦. 而且我的线程框架本来打算完全独立的,即我准备调用一些挂在中间件的服务,那样我就更加不能让那些服务按照我的规则来写了,所以感觉很棘手. 不然我就不会提出这种想法了.
DreamFreeLancer 2009-09-27
  • 打赏
  • 举报
回复
Cancle是有办法的,你可以调用pthread_cancle函数,但它也仅在所谓的Cancle Point才生效,其它所谓Suspend和Resume应该说只能基于线程框架和使用它的程序员之间约定规则才可能实现(通常也就是等待一些同步对象),LZ想实现完全透明的方式好象不太现实。
程英杭 2009-09-27
  • 打赏
  • 举报
回复
非常感谢daidodo对我的回答,但这个还不能达到我要的目的.
其实,我也曾经考虑类似JAVA的线程使用方式,即要使用线程的继承一个Runnable,Runnable里面也就只有一个纯虚函数,但这种方式有点缺陷,就是必须继承Runnable才能使用线程类,这个对于在C++里面来说可能比较不方便,因为很多现有程序都是面向过程开发的。
另外,我目前比较常见的是批处理数据中使用线程,由于数据量很大,即要循环处理的数据很多,可能处理时间很长,类似如下代码
open(一个文件)

while(1)
{
read(读文件)
if(eof)
break;
处理文件
}
close(关闭一个文件)
由于执行时间太长,那么,也就是需要在执行过程中允许其他线程干预它,让他暂时性的挂起作业,而并非它自己本身发起的,即业务程序只负责按照业务规则把要处理的事情处理完

但是,我不希望业务程序增加和控制相关的代码
open(一个文件)

while(1)
{
thread->RegisterSuspendPoint();
thread->RegisterCancelPoint();
read(读文件)
if(eof)
break;

处理文件
}

如果增加这两个函数的调用,即通过条件变量和锁确实很容易就达到目的,但这样不是很理想,因为每个业务函数都要增加这段代码。且增加这段代码还得注意很多事情,即增加的位置是否会导致文件或其他公共数据被加锁而不能得到释放,因为这样往往就可能会导致锁超时,甚至锁等待。

不过,这个要真的没有很好的办法,也就只能这样了。
不过我很想知道的是在.Net中,他们怎么实现的,因为它的线程函数即使没有任何循环动作,它也能让其挂起。
whg01 2009-09-26
  • 打赏
  • 举报
回复
在类中加一些控制信息,用此类生成的线程要调用类的某个方法,在这个方法中控制线程的Suspend,Resume.
  • 打赏
  • 举报
回复
http://www.linuxidc.com/Linux/2008-09/15935.htm

用等待条件变量来实现类似Suspend和Resume的功能。

楼主的问题问得很好啊,以前从来没考虑过这个问题。
有空好好想想怎么搞。
程英杭 2009-09-26
  • 打赏
  • 举报
回复
提供注册函数,写线程执行函数的就不是很方便了,我目前只对Cancel做了这种处理,但我不想Suspend和Resume 也用类似的方法。大家帮我考虑下阿 我想我封装的类 和.net的Thread 类相似 这样使用的时候会比较方便
woods2001 2009-09-26
  • 打赏
  • 举报
回复
mark!
thy38 2009-09-26
  • 打赏
  • 举报
回复
Thread类提供一个注册函数,让函数先注册一些相应的信息就方便了。

64,677

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧