ILE RPG でマルチスレッド・アプリケーション (2) - 排他制御 (mutex) -

前回のプログラムに、排他制御を使用して両方のスレッドから共有して更新される値をくわえてみました。

     H THREAD(*CONCURRENT)                                                                          
     H BNDDIR('QC2LE')                                                                              
     H DFTACTGRP(*NO)                                                                               
     H OPTION(*SRCSTMT : *NOUNREF)                                                                  
      /COPY QSYSINC/QRPGLESRC,PTHREAD                                                               
      *                                                                                             
     D NUMTHREADS      C                   10                                                       
      *                                                                                             
     D do_add1         PR            10i 0 extproc('do_add1')                                       
     D    rc1                          *   value                                                    
      *                                                                                             
     D do_add2         PR            10i 0 extproc('do_add2')                                       
     D    rc2                          *   value                                                    
      *                                                                                             
     D rc1             S             10i 0 inz(100)                                                 
     D rc2             S             10i 0 inz(10)                                                  
      *                                                                                             
     D checkResults    PR                  extproc('checkResults')                                  
     D    string                   1000a   varying const                                            
     D    val                        10i 0 value                                                    
      *                                                                                             
     D print           PR                  extproc('print')                                         
     D    msg                      1000a   varying const                                            
      *                                                                                             
     D fmtThreadId     PR            17a   varying                                                  
      *                                                                                             
     D CEETREC         PR                                                                           
     D    cel_rc_mod                 10i 0 OPTIONS(*OMIT)                                           
     D    user_rc                    10i 0 OPTIONS(*OMIT)                                           
      *                                                                                             
     D sleep           PR                  extproc(*CWIDEN : 'sleep')                               
     D    secs                       10i 0 value                                                    
      *                                                                                             
     D thread          DS                  likeds(pthread_t)                                        
     D                                     dim(NUMTHREADS)                                          
      *                                                                                             
     D rc              S             10i 0 inz(0)                                                   
      *                                                                                             
     D mutex           DS                  likeds(pthread_mutex_t)                                  
     D                                     STATIC(*allthread)                                       
      *                                                                                             
     D sharedData      S             10i 0 inz(0)                                                   
     D                                     STATIC(*allthread)                                       
      *                                                                                             
      /free                                                                                         
                                                                                                    
          print ('Initialize mutex') ;                                                              
          mutex = PTHREAD_MUTEX_INITIALIZER ;                                                       
                                                                                                    
          print ('Create/start a thread') ;                                                         
          rc = pthread_create(thread(1) : *OMIT                                                     
                                  :%paddr(do_add1) : %addr(rc1)) ;                                  
          checkResults('pthread_create() ' : rc) ;                                                  
                                                                                                    
          print ('Create/start another thread') ;                                                   
          rc = pthread_create(thread(2) : *OMIT                                                     
                             :%paddr(do_add2) : %addr(rc2)) ;                                       
          checkResults('pthread_create() ' : rc) ;                                                  
                                                                                                    
          sleep(10) ;                                                                               
                                                                                                    
          print ('Sync threads') ;                                                                  
          rc = pthread_join  (thread(1) : *OMIT) ;                                                  
          checkResults('pthread_join() ' : rc) ;                                                    
                                                                                                    
          print ('Sync another thread') ;                                                           
          rc = pthread_join  (thread(2) : *OMIT) ;                                                  
          checkResults('pthread_join() ' : rc) ;                                                    
                                                                                                    
          print ('do_add1 returns ' + %char(rc1)) ;                                                 
          print ('do_add2 returns ' + %char(rc2)) ;                                                 
          print ('Shared Data is  ' + %char(SharedData)) ;                                          
                                                                                                    
          print ('Destroy mutex') ;                                                                 
          rc = pthread_mutex_destroy (mutex) ;                                                      
          checkResults ('pthread_mutex_destroy() ' : rc ) ;                                         
                                                                                                    
          return ;                                                                                  
                                                                                                    
      /end-free                                                                                     
      *                                                                                             
     P do_add1         B                                                                            
     D do_add1         PI            10i 0                                                          
     D    parm                         *   value                                                    
     D r1              S             10i 0 based(parm)                                              
     D i               S             10i 0                                                          
      /free                                                                                         
          print ('Enter do_add1 ') ;                                                                
          for i = 1 to 30 ;                                                                         
             sleep(1) ;                                                                             
             r1  += 1 ;                                                                             
             print ('do_add1 : ' + %char(r1 )) ;                                                    
                                                                                                    
             rc = pthread_mutex_lock (mutex) ;                                                      
             checkResults ('pthread_mutex_lock() ' : rc ) ;                                         
             sharedData  += 1 ;                                                                     
             rc = pthread_mutex_unlock (mutex) ;                                                    
             checkResults ('pthread_mutex_unlock() ' : rc ) ;                                       
             print ('do_add1 Shared: ' + %char(sharedData )) ;                                      
                                                                                                    
          endfor ;                                                                                  
          rc1 = r1 ;                                                                                
          return 0 ;                                                                                
      /end-free                                                                                     
     P do_add1         E                                                                            
      *                                                                                             
     P do_add2         B                                                                            
     D do_add2         PI            10i 0                                                          
     D    parm                         *   value                                                    
     D r2              S             10i 0 based(parm)                                              
     D i               S             10i 0                                                          
      /free                                                                                         
          print ('Enter do_add2 ') ;                                                                
          for i = 1 to 50 ;                                                                         
             sleep(1) ;                                                                             
             r2   += 1 ;                                                                            
             print ('do_add2 : ' + %char(r2 )) ;                                                    
                                                                                                    
             rc = pthread_mutex_lock (mutex) ;                                                      
             checkResults ('pthread_mutex_lock() ' : rc ) ;                                         
             sharedData  += 1 ;                                                                     
             rc = pthread_mutex_unlock (mutex) ;                                                    
             checkResults ('pthread_mutex_unlock() ' : rc ) ;                                       
             print ('do_add2 Shared: ' + %char(sharedData )) ;                                      
                                                                                                    
          endfor ;                                                                                  
          rc2 = r2 ;                                                                                
          return 0 ;                                                                                
      /end-free                                                                                     
     P do_add2         E                                                                            
      *                                                                                             
      * Utility Procedures                                                                          
      *                                                                                             
     P checkResults    B                   EXPORT                                                   
     D checkResults    PI                                                                           
     D    string                   1000a   varying const                                            
     D    val                        10i 0 value                                                    
      /free                                                                                         
          if val <> 0 ;                                                                             
             print ('Thread(' + fmtThreadId() + ') : ' + string) ;                                  
             CEETREC (*OMIT : *OMIT) ;                                                              
          else ;                                                                                    
             /if defined(LOG_ALL_RESULTS)                                                           
             print (string + ' completed normally with ' + %char(val)) ;                            
             /endif                                                                                 
          endif ;                                                                                   
      /end-free                                                                                     
     P checkResults    E                                                                            
      *                                                                                             
     P print           B                   EXPORT                                                   
     D print           PI                                                                           
     D    msg                      1000a   varying const                                            
     D printf          PR              *   extproc('printf')                                        
     D    template                     *   value options(*string)                                   
     D    string                       *   value options(*string)                                   
     D    dummy                        *   value options(*nopass)                                   
     D NEWLINE         C                   x'15'                                                    
      /free                                                                                         
          printf ('%s' + NEWLINE : msg) ;                                                           
      /end-free                                                                                     
     P print           E                                                                            
      *                                                                                             
     P fmtThreadId     B                   EXPORT                                                   
     D fmtThreadId     PI            17a   varying                                                  
     D pthreadId       DS                  likeds(pthread_id_np_t)                                  
     D buf             S           1000a                                                            
     D sprintf         PR              *   extproc('sprintf')                                       
     D    buf                          *   value                                                    
     D    template                     *   value options(*string)                                   
     D    num1                       10u 0 value                                                    
     D    num2                       10u 0 value                                                    
     D    dummy                        *   value options(*nopass)                                   
      /free                                                                                         
          pthreadId = pthread_getthreadid_np() ;                                                    
          sprintf (%addr(buf)                                                                       
                  : '%.8x % 8x'                                                                     
                  : pthreadId.intId.hi                                                              
                  : pthreadId.intId.lo ) ;                                                          
          return  %str(%addr(buf)) ;                                                                
      /end-free                                                                                     
     P fmtThreadId     E                                                                            

基本的なプログラムの流れ

排他制御には mutex (Mutually Exclusive 相互排他) というものを使います。

     D mutex           DS                  likeds(pthread_mutex_t)                                  
     D                                     STATIC(*allthread)                                       
          mutex = PTHREAD_MUTEX_INITIALIZER ;                                                       

pthread を生成する元のプロシージャで↑のように初期化した後、pthread で実行させるためのプロシージャの中で↓のように共用する変数の前後でロック/アンロックを行う、という仕組みです。

             rc = pthread_mutex_lock (mutex) ;                                                      
             sharedData  += 1 ;                                                                     
             rc = pthread_mutex_unlock (mutex) ;                                                    

必要なくなったところで、↓のように削除します。

          rc = pthread_mutex_destroy (mutex) ;                                                      

実行例

スレッドがメインのものから 2つ生成されています。前回と同様ですね。

スタックを見ても前回と同様です。mutex のロック/アンロックはさすがに速すぎて、普通に動いている限りここで見るのは難しそうです。

出力を見てみましょう。

ちょっと長いですが、スレッドの処理がやはりけっこう入り乱れていること、共用の変数がそれでも順番にきちんとカウントアップされていっていることが確認できますね。

[Top Pageに戻る]

Ads by TOK2