歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

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
Copyright © Linux教程網 All Rights Reserved