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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值