Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1372642
  • 博文数量: 284
  • 博客积分: 3251
  • 博客等级: 中校
  • 技术积分: 3046
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-26 17:23
文章分类

全部博文(284)

文章存档

2019年(2)

2018年(5)

2015年(19)

2014年(13)

2013年(10)

2012年(235)

分类: LINUX

2012-05-04 18:42:26

1.基础线程创建:

#include
#include
#include

void * print_id( void * arg ) 
       //!> 这是线程的入口函数                               
{
    printf("The Current process is: %d \n", getpid());                                //!> 当前进程ID   
    printf( "The Current thread id : %d \n", (unsigned)pthread_self() );    //!> 注意此处输出的子线程的ID
}

int main( )
{
    pthread_t        t;
    int                 t_id;
   
    t_id = pthread_create( &t, NULL, print_id, NULL );        //!> 简单的创建线程
   
    if( t_id != 0 )                        //!> 注意创建成功返回0                               
    {
        printf("\nCreate thread error...\n");
        exit( EXIT_FAILURE );
    } 
    sleep( 1 );
    printf("\nThe Current process is: %d \n", getpid());                         //!> 当前进程ID       
    printf( "The Main thread id : %d \n", (unsigned)pthread_self() );    //!> 注意输出的MAIN线程的ID
    return 0;
}



2.测试线程的创建和退出

#include
#include
#include
#include

void * entrance_1( void * arg )                //!> 第一个创建的线程的入口函数
{
    printf( " thread 1 id == %d , run now ... \n", ( unsigned )pthread_self() );
    sleep( 3 );
    return ( ( void * ) 1 );
}

void * entrance_2( void * arg )                //!> 第二个创建的线程的入口函数
{
    printf( " thread 2 id == %d , run now ... \n", ( unsigned )pthread_self() );
    sleep( 3 );
    return ( ( void * ) 2 );
}

int main( )
{
    pthread_t        t1 = -1;    //!> 最好是初始化:因为下面的pthread_join是需要判断是否成功在输出的
    pthread_t        t2 = -1;
    int              tid1;
    int              tid2;
    void     *        ret;
   
    tid1 = pthread_create( &t1, NULL, entrance_1, NULL );    //!> 简单的创建线程
    tid2 = pthread_create( &t2, NULL, entrance_2, NULL );
   
    if( tid1 != 0 || tid2 != 0 )    //!> 创建线程失败                   
    {
        printf( "Create thread error...\n" );
        exit( EXIT_FAILURE );
    }
   
    if( t1 != -1 )                //!> 也就是线程还没有结束
    {
        if ( pthread_join( t1, &ret ) == 0 )    //!> join success
        {
            printf( " thread 1 get the return of pthread_join == %d \n", 2 );/ )
 {
     pthread_mutex_init( &mutex, NULL );        //!> 初始化为默认的互斥锁
    
     printf("主函数:创建2个子线程...\n");
    
     create_two_thread();        //!> 创建2个线程
    
     printf("主函数:等待线程完成任务...\n");
    
     wait_two_thread();        //!> 等待线程完成任务
                                 //!> 线程任务完成才可以执行下面代码
     printf("线程任务完成...\n");
    
     printf("Num == %d \n\n", num);
    
     return 0;
 }
 
4.双线程处理:冒泡排序算法

//        双线程处理冒泡排序(多线程也一样)
//        实现从“小”--->“大”排序

#include
#include
#include
#include

int g_arr[] = { 10, 23, 12, 34, 5, 29, 90, 9, 78, 44 };        //!> 全局的要排序的数组
pthread_t                thread[2];               //!> 两个线程
pthread_mutex_t        mutex;                //!> 互斥锁

int                         g_i = 0;                     //!> 全局的剩余排列次数

//!> 打印数组
void print_array()
{
    int i;
    for( i = 0; i < 10; i++ )
    {
        printf( " %d ", g_arr[i] );
    }
    printf("\n");
}

//!> 交换元素
void swap_elem( int * a, int * b )
{
    int temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

//!> 线程1入口函数
void * entrance_1( void * arg )
{
    int j;
    for( g_i = 0; g_i < 10; g_i++ )    //!> 外层循环
    {
        pthread_mutex_lock( &mutex );        //!> 加锁
       
        printf( "线程1后台执行排序...\n" );
       
        for( j = 0; j < ( 10 - g_i - 1 ); j++ )    //!> 内层循环
        {
            if( g_arr[j] > g_arr[j+1] )
            {
                swap_elem( &g_arr[j], &g_arr[j+1] );
            }
        }
       
        pthread_mutex_unlock( &mutex );    //!> 解锁
       
        sleep( 1 );
    }
}

//!> 线程2入口函数
void * entrance_2( void * arg )
{
    int j;
    for( g_i = 0; g_i < 10; g_i++ )    //!> 外层循环
    {
        pthread_mutex_lock( &mutex );        //!> 加锁
       
        printf( "线程2后台执行排序...\n" );
           
        for( j = 0; j < ( 10 - g_i - 1 ); j++ )    //!> 内层循环
        {
            if( g_arr[j] > g_arr[j+1] )
            {
                swap_elem( &g_arr[j], &g_arr[j+1] );
            }
        }
   
        pthread_mutex_unlock( &mutex );    //!> 解锁

        sleep( 2 );   
    }
}

//!> 创建2个线程
void create_two_thread()
{
    memset( &thread, 0, sizeof( thread ) );            //!> 初始化为0(作为下面的判断进程是否创建OK依据)
   
    if( ( pthread_create( &thread[0], NULL, entrance_1, NULL ) ) == 0 )
    {
        printf("线程1创建OK ...\n");
    }
    else
    {
        printf("线程1创建Error ...\n");
        exit( EXIT_FAILURE );
    }
   
    if( ( pthread_create( &thread[1], NULL, entrance_2, NULL ) ) == 0 )
    {
        printf("线程2创建OK ...\n");
    }
    else
    {
        printf("线程2创建Error ...\n");
        exit( EXIT_FAILURE );
    }
   
}

//!> 线程执行与等待
void do_and_wait()
{
    if( thread[0] != 0 )//!> 由于在create_two_thread中初始化=0,if床架ok,那么不可能还是0
    {
        pthread_join( thread[0], NULL );    //!> 等待线程1结束,不结束不执行下面代码
        printf("线程1执行结束退出...\n");
    }
    else
    {
        printf("线程1创建Error...\n");
        exit( EXIT_FAILURE );
    }
   
    if( thread[1] != 0 )
    {
        pthread_join( thread[1], NULL );    //!> 等待线程1结束,不结束不执行下面代码
        printf("线程2执行结束退出...\n");
    }
    else
    {
        printf("线程2创建Error...\n");
        exit( EXIT_FAILURE );
    }
   
}

int main( )
{
    printf("主函数:下面创建2个线程共同处理冒泡排序...\n");
   
    pthread_mutex_init( &mutex, NULL );
   
    print_array();                //!> 打印排序前的结果
   
    create_two_thread();        //!> 创建线程
    do_and_wait();            //!> 执行线程and等待
   
    printf( "排序完成:\n" );

    print_array();                //!> 打印排序后的结果
       
    return 0;
}

5.线程清理处理程序

//        线程清理处理程序TEST

#include
#include
#include

void clean(void *arg)
{
    printf("清理: %s \n", (char *)arg);
}

void * entrance( void * arg )
{
    printf("线程开始...\n");
   
    pthread_cleanup_push( clean, "线程处理程序1" );
    pthread_cleanup_push( clean, "线程处理程序2" );
   
    printf("pthread clean 完成...\n");
   
    sleep(3);
   
    pthread_exit((void *)0);        //!> 我们知道:清理函数只有在异常退出时候才会做一些清理工作
                                                //!> 所以此处的退出是异常退出来测试的!
   
    pthread_cleanup_pop(0);    
    pthread_cleanup_pop(0);    
   
   
   
}

int main( )
{
    pthread_t     tid;
    void     *     ret = NULL;
   
    if( ( pthread_create( &tid, NULL, entrance, (void *)1 ) ) != 0 )
    {
        printf("创建线程失败...\n");
        exit( EXIT_FAILURE );
    }
   
    pthread_join( tid, &ret );       
   
    if( ret )                            //!> 注意此处相当于是抛出异常
    {                                //!> 避免子线程的异常退出造成的空指针情况
        printf( "结束:code == %d\n", *( ( int * ) ret) );
    }
   
    return 0;
}

/////////////////////////////////////////////////////////////
//    DEMO——2

#include
#include
#include

void clean( void * arg )
{
    printf("清理函数执行...\n");
}

void * entrance( void * arg )
{
    int old_type, old_state;
    int i = 0;
   
    pthread_cleanup_push( clean, NULL );    //!> 设置清理函数
    printf("下面设置对本线程的“取消”无效\n");
    pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &old_state );
                                                //!> 设置对本线程的“取消”无效
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,&old_type);    //>>>>>>>>>>> 目标句1
   
    while( 1 )
    {
        ++i;
        printf("子线程runing...\n");
        sleep( 2 );
        if( 5 == i )
        {
            printf("下面取消设置对本线程的“取消”无效\n");
            pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_state);
        }
    }
   
    pthread_cleanup_pop( 0 );
}

int main( int argc, char ** argv )
{
    pthread_t    tid;
    int               res;
    void *          ret;
   
    pthread_create( &tid, NULL, entrance, NULL );
    sleep( 2 );
    printf("请求子线程退出...\n");
    pthread_cancel( tid );            //!> 请求子线程退出
   
    res = pthread_join( tid, &ret );    //!> 等待子线程退出
   
    if( ret != PTHREAD_CANCELED )    //!> 非安全退出
    {
        printf("pthread_join 失败...\n");
        exit( EXIT_FAILURE );
    }
    else
    {
        printf("Success..");
    }
       
    exit( EXIT_SUCCESS );   
}


    分析:
        没有加上“目标句”的结果是:
                                        下面设置对本线程的“取消”无效
                                        子线程runing...
                                        请求子线程退出...
                                        子线程runing...
                                        子线程runing...
                                        子线程runing...
                                        子线程runing...
                                        下面取消设置对本线程的“取消”无效
                                        子线程runing...                        //!> 比下面多的
                                        清理函数执行...
                                        Success..                                //!> 与下面不一样的
                                       
      加上后:
                                        下面设置对本线程的“取消”无效
                                        子线程runing...
                                        请求子线程退出...
                                        子线程runing...
                                        子线程runing...
                                        子线程runing...
                                        子线程runing...
                                        下面取消设置对本线程的“取消”无效
                                        清理函数执行...
                                        pthread_join 失败...                    //!> 与上面不一样的
                                       
       这句的作用是将取消类型设置为PTHREAD_CANCEL_ASYNCHRONOUS,即取消请求会被立即响应                                   
       那么就不会再次进入等待下一个“取消点”再进行取消!!!
   
       注意:if在while中没有sleep,那么程序会无限run,我们知道sleep是相当于是释放一下线程,那么此时的主线程中的cancel信号又被 接收到,那么if本函数可以响应了,那么就cancle了,if将sleep去掉,那么死循环!再次解释:所谓pthread_cancel仅仅是请求某 个线程退出,那么究竟是不是退出还要看state和type的设置!                   



6. pthread_once 工作原理code


//        pthread_once 函数使用

#include
#include
#include

pthread_once_t        once = PTHREAD_ONCE_INIT;    //!> once宏赋值

//!> 初始化执行函数
void once_init( void )
{
    printf("初始化成功! 我的ID == %d\n", (unsigned)pthread_self());
}

//!> 线程入口函数
void * entrance( void * arg )
{   
    printf("子线程:ID == %d \n", (unsigned)pthread_self());
    //!> once = PTHREAD_ONCE_INIT;        //!> 测试使用(下面的要求)
    pthread_once( &once, once_init );        //!> 此处也有初始化
}

//!> main函数
int main( int argc, char * argv[] )
{
    pthread_t        pid;
   
    pthread_create( &pid, NULL, entrance, NULL );

    printf("主函数ID == %d \n", (unsigned)pthread_self());
   
//!>    pthread_join( pid, NULL );            //!> 分析点
   
    pthread_once( &once, once_init );    //!> 调用一次初始化函数
   
    pthread_join( pid, NULL );
   
    return 0;
}

        if pthread_join是在主函数初始化后面,那么就是主函数初始化的
        结果是: 主函数ID == 441960192
                       初始化成功! 我的ID == 441960192
                      子线程:ID == 433944320
        显而易见是主函数初始化的!
       
        if pthread_join是在之前,那么就是要等待子函数执行ok后才执行自己的下面代码
        但是此时已经初始化ok了,所以不在初始化!
        结果是:主函数ID == 210818816
                      子线程:ID == 202802944
                      初始化成功! 我的ID == 202802944
        显然是子函数执行的初始化!

        本质:   其实就是操作once变量而已,与互斥变量的本质是一样的!!!
                      我们可以这样测试在entrance中加入once = PTHREAD_ONCE_INIT;
        结果是:主函数ID == 1590228736
                      初始化成功! 我的ID == 1590228736
                      子线程:ID == 1582212864
                      初始化成功! 我的ID == 1582212864
       
        感兴趣的可以使用pthread_mutex_t 的互斥变量处理,效果一样!
        还有最最简单的就是bool值处理!此处不建议!

7.pthread_key_create线程键 与 线程存储

#include
#include
#include

pthread_once_t        once = PTHREAD_ONCE_INIT;
pthread_key_t        key;            //!> 键值
   
int                         g_val = 10;    //!> 传说中的独享值,呵呵

void once_init_key()
{   
    if( pthread_key_create( &key, NULL ) == 0 )    //!> 创建线程键值
    {                                                    //!>
        printf("创建线程键OK ...\n");
    }
}

void * entrance( void * arg )
{
    int * val;
    printf("子线程:ID == %d \n", (unsigned)pthread_self());
   
    pthread_setspecific( key, &g_val );               //!> 将 g_val 作为一个每个进程的独享值
   
    val = ( int * )pthread_getspecific( key );        //!> 取出那个值
                                                        //!> 此后对于这些量都有自己的处理方式,
                                                        //!> 名称相同但是内容不同!!!   
                                                        //!> 对于文件的处理是最好的!!!
    printf("ID == %d, Value == %d\n",  (unsigned)pthread_self(), *val);
}


int main( )
{
    pthread_t        tid, tid2;
    void     *      ret1;
    void     *     ret2;
   
    if( pthread_create( &tid, NULL, entrance, NULL ) != 0 )            //!> 线程1
    {
        printf("创建线程1失败...\n");
        exit( EXIT_FAILURE );
    }
   
    if( pthread_create( &tid2, NULL, entrance, NULL ) != 0 )            //!> 线程2
    {
        printf("创建线程2失败...\n");
        exit( EXIT_FAILURE );
    }
           
    printf("主函数:ID == %d \n", (unsigned)pthread_self());
       
    //!>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   
   
    pthread_once( &once, once_init_key );    //!> 创建一个键值
   
    //!>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   
    printf("下面等待子线程执行ok... \n");
   
    pthread_join( tid, &ret1 );                    //!> 等待线程( 必不可少 )
    pthread_join( tid2, &ret2 );
   
    return 0;
}

结果:
    主函数:ID == 1588877056
    创建线程键OK ...
    子线程:ID == 1580861184
    ID == 1580861184, Value == 10
    下面等待子线程执行ok...
    子线程:ID == 1572468480
    ID == 1572468480, Value == 10
阅读(1496) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~