Linux 多线程编程( POSIX )


1.基础线程创建:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void * print_id( void * arg)       //!>这是线程的入口函数                        
{
    printf("TheCurrent process is: %d \n",getpid());                           //!>当前进程ID   
    printf( "TheCurrent 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( "TheMain thread id : %d \n", (unsigned)pthread_self());   //!> 注意输出的MAIN线程的ID
    return0;
}



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

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>

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 <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>

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 )
{
    inttemp;
    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();            //!> 打印排序后的结果
      
    return0;
}

5.线程清理处理程序

//      线程清理处理程序TEST

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

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) );
    }
   
    return0;
}

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

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

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

void * entrance( void * arg )
{
    intold_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 <stdio.h>
#include <stdlib.h>
#include <pthread.h>

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 );
   
    return0;
}

       ifpthread_join是在主函数初始化后面,那么就是主函数初始化的
       结果是: 主函数ID== 441960192
                  初始化成功! 我的ID == 441960192
                 子线程:ID == 433944320
      显而易见是主函数初始化的!
      
       ifpthread_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 <stdio.h>
#include <stdlib.h>
#include <pthread.h>

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 );
   
    return0;
}

结果:
    主函数:ID ==1588877056
    创建线程键OK...
    子线程:ID ==1580861184
    ID ==1580861184, Value == 10
   下面等待子线程执行ok...
    子线程:ID ==1572468480
    ID ==1572468480, Value == 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9..
  • 12
  • 下一页

相关内容