免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1110 | 回复: 0
打印 上一主题 下一主题

pthread之线程取消 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-23 16:27 |只看该作者 |倒序浏览

pthread之线程取消
第二春刚来的时候,和我讨论过一个关于程序多线程的结构的问题,打算采用pthread_cancel来处理,为了满足下面的要求,于是有了下面的代码:)  前两天再和春讨论,我发现春懂的比我懂的多多了:(
       线程取消并不常用,通常做为多线程编程中的高级话题,更为详细的描述请看多线程程序设计>>一书,此书是多线程编程的大宝典呀!对各对概念做了详细的描述。此外,环境高级编程>>涉及了大量posix中并未详述的内容。下面提个大概的内容。
Phread_cancel是一种请求,而不是粗暴的命令。Phread允许线程控制自己的结束,它能恢复程序不变量并解锁互斥锁支持推迟取消,取消只能发生在取消点:) 取消点的概念去看书吧,是个比较复杂的问题取消状态有三种:分别由状态(disable,enable)与类型( deferred,
     asynchronous)组合而成,分别为off, deferred, async.避免使用异步取消,这个东西很难用对,也用处不大:)利用pthread_testcancel来构建自己的函数,使其能够在该函数中被取消
我们的需求:
    1. 利用pthread cancel的属性,保证某一段代码完整的执行(面对pthread_cancel互斥量不能做到这一点
在要完整执行的代码的前后,设置禁用pthread_cancel在对要求完整执行的线程发出取消命令之后,用join等返回
    2. 线程send发送信号给digest让其运行,但如果digest不在运行状态,则该信号丢失 线程send在收到cancel之后不保证事件处理,直接退出
    3. 线程send在收到cancel之后不保证事件处理,直接退出
    4. 当digest线程不再等待而在执行过程时(比如sleep)时,sender发送的信号被丢失
    5. sender发送5个信号给digest,可能digest最终只能消化3个信号,它只保证这三个信号被完整执行,而不中断,但不保存所有的信号都被执行。可能通过输出看到digest在取消信号发出之后依然执行完成最后的一次处理。
    6. 如果要保证所有发出的信号都被执行,有两种方式:
当digest完成自己的信号之后发送信号给sender(在等待)利用消息队列,digest从消息队列中取出sender不断发出的信号,依次处理,处理完后退出
首先来看看整个目录的结构:
dongq@DongQ:~/test$ tree thread_cancel
thread_cancel
|-- Makefile   -make
|-- main.c    --主线程
|-- main.h     --数据结构
`-- thread.c   --线程体
0 directories, 4 files
我们一个个来看,先看看main.h,在它里面只定义了一个数据结构和两个全变量:
#ifndef MAIN_H
#define MAIN_H
#include
#include
#include
#include
#include
#include
#include
pthread_mutex_t mutex;
pthread_cond_t cond;
typedef struct test
{
        int a;  //digest线程休息时间间隔
        int b;  //sender线程休息时间间隔
}Test;
#endif
再来看看main.c中有什么东西,在主线程中,创建一个 send线程,一个digest线程,相当于send告诉digest去做什么,digest就
尽自己最大的努力去做此事。
#include "main.h"
extern void * sendData( void * arg );
extern void * digestData( void * arg );
void my_exit();
pthread_t send_pid;
pthread_t digest_pid;
int main()
{
        Test x = { 2, 33 };  
        printf(
"PTHREAD_CANCEL_ENABLE:%d PTHREAD_CANCEL_DISABLE:%d\n",
                                      PTHREAD_CANCEL_ENABLE,
PTHREAD_CANCEL_DISABLE);
        pthread_mutex_init( &mutex,
NULL );
        pthread_cond_init( &cond, NULL
);
        
        //创建digest线程
        if ( pthread_create(
&digest_pid, 0, digestData, &x ) )
        {
               printf( "Create
digestData thread error\n" );
               exit( -1 );
        }
        
        //创建sender线程
        if ( pthread_create(
&send_pid, 0, sendData, &x ) )
        {
               printf( "Create
sendData thread error\n" );
               exit( -1 );
        }
       //等待一段时间
        sleep( x.b / 3 );
        my_exit();
        
        return 0;
}
void my_exit()
{
        printf(" cancel
sendpid\n");
        //通知send线程通出,send则立即退出
        pthread_cancel( send_pid );
        printf(" cancel
disgestpid\n");
        //通知digest线程退出
, digest将在执行完当前的任务之后再退出
        pthread_cancel( digest_pid );
        printf(" join
sendpid\n");
        pthread_join( send_pid, 0 );
        printf(" join
disgestpid\n");
        pthread_join( digest_pid, 0 );
        printf( "parent exit.\n"
);
}
现在来看看子线程体,是如何来满足我们的需求的:
#include "main.h"
void * digestData( void * arg )
{
        int status;
        Test * x = ( Test * )arg ;
        while( 1 )
        {
               pthread_mutex_lock(
&mutex );
               status = pthread_cond_wait(
&cond, &mutex );
               pthread_mutex_unlock(
&mutex );
               if ( status != 0 )
               {
                       printf(
"condition wait failure!!!\n" );
               }
               int c = x->a;
               printf( "digest sleep
time: %d\n", c );
               //设置线程,禁用线程取消功能
               pthread_setcancelstate(
PTHREAD_CANCEL_DISABLE, &status );
               if ( status !=
PTHREAD_CANCEL_ENABLE )
               {
                       printf(" !!set
cancel state failure!!!\n");
               }
               while( c-- )  //线程休眠,取消有机会在这个时间段发生,但取消只被记下,不马上退出,保证当前任务执行完成
               {
                       printf(
"digest\n" );   //虽然是个取消点,但是取消被diable了,这样系统将会有一个未被解决的取消
                       sleep ( 1 );
               }
               printf( "digest the
data from sender!!!\n" );
               //启用取消功能,默认取消延迟处理取消请求
                pthread_setcancelstate(
PTHREAD_CANCEL_ENABLE, &status );
               if ( status !=
PTHREAD_CANCEL_DISABLE )
               {
                       printf("**set
cancel state failure!!!%d\n", status);
               }
        }
        return (void *)0;
}
//当send在运行时,得到取消请求后,将在下一个取消点退出
void * sendData( void * arg )
{
        Test * x = ( Test * )arg ;
        int c = x->b;

        printf( "sender sleep
time:%d\n", c );
        while( c-- )
        {
               printf( "send\n"
);
               sleep( 1 );
                //每隔几秒才发送信号
               if ( c % 3 )
               {
                       pthread_mutex_lock(
&mutex );
                       printf( "send
command to digest data\n" );
                       pthread_cond_signal(
&cond );
                       pthread_mutex_unlock(
&mutex );
               }
        }
        return (void *)0;
}
在清除处理函数中等待不是一个好主意(因为毕竟该线程是用来清除的,而不是用来等待某件事的发生)。
但是如果你的清除处理函数确实需要等待一些东西,它也会工作得很好。


               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/94916/showart_1908247.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP