1. 程式人生 > >jni中的執行緒, 同步以及生產者消費者模式

jni中的執行緒, 同步以及生產者消費者模式

  • 編譯環境centos6.×64

執行緒建立以及結束

#include <pthread.h>
pthread_create (thread, attr, start_routine, arg) 

連線和分離執行緒

pthread_join (threadid, status) 
pthread_detach (threadid) 

pthread_join() 子程式阻礙呼叫程式,直到指定的 threadid 執行緒終止為止。

例子1


#include <unistd.h>
#include <pthread.h>
void* thr_fun(void* arg){ char* no = (char*)arg; int i = 0; for(; i < 10; i++){ printf("%s thread, i:%d\n",no,i); if(i==5){ //執行緒退出(自殺) pthread_exit(2); //他殺pthread_cancel } } return 1; } void main(){ //執行緒的引用
pthread_t tid; pthread_create(&tid,NULL,thr_fun,"執行緒1"); void *rval; pthread_join(tid,&rval); printf("執行緒結束%d\n",rval); }

程式碼意思,pthread_create開啟了執行緒,當thr_fun遍歷10次,當第5次的時候退出執行緒.

  • 編譯命令: gcc test1.c -o main -lpthread

  • 執行 結果

[root@host threadDemo]# ./main
執行緒1 thread, i:
0 執行緒1 thread, i:1 執行緒1 thread, i:2 執行緒1 thread, i:3 執行緒1 thread, i:4 執行緒1 thread, i:5 執行緒結束 2

例子2

多執行緒問題


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

int i=0;
void* thr_fun(void* arg){
        char* no = (char*)arg;

        for(; i < 10; i++){
                printf("%s thread, i:%d\n",no,i);
                sleep(1);
        }
        i=0;
        return 1;

}
void main(){
        //執行緒的引用
        pthread_t tid,tid2;
        pthread_create(&tid,NULL,thr_fun,"執行緒1");
        pthread_create(&tid2,NULL,thr_fun,"執行緒2");

        void *rval;
         pthread_join(tid,&rval);
         pthread_join(tid2,&rval);
        printf("執行緒結束 %d",rval);

}

編譯出來main2 執行後 每隔一秒先列印執行緒2 然後列印i

可以看出 是兩個執行緒搶佔使用thr_fun 出現這種結果 .

如果我想每個執行緒單獨列印i ,應該怎麼做 : 同步

[root@host threadDemo]# gcc 02.c -o main2 -lpthread
[root@host threadDemo]# ls
02.c  main  main2  test1.c  thread01.c
[root@host threadDemo]# ./main2
執行緒2 thread, i:0
執行緒1 thread, i:0
執行緒2 thread, i:1
執行緒1 thread, i:2
執行緒2 thread, i:3
執行緒1 thread, i:4
執行緒2 thread, i:5
執行緒1 thread, i:6
執行緒2 thread, i:7
執行緒1 thread, i:8
執行緒2 thread, i:9
執行緒2 thread, i:1
執行緒2 thread, i:2
執行緒2 thread, i:3
執行緒2 thread, i:4
執行緒2 thread, i:5
執行緒2 thread, i:6
執行緒2 thread, i:7
執行緒2 thread, i:8
執行緒2 thread, i:9
執行緒結束 1

執行緒的同步

  • 現在的目的: 第一個執行緒全部輸出完成後,第二個執行緒再去列印.

int pthread_mutex_init 是一條指令,是中斷指令的標識。 該函式用於C函式的多執行緒程式設計中,互斥鎖的初始化。 (類似 synchronized 作用)

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); posix下抽象了一個鎖型別的結構:ptread_mutex_t。通過對該結構的操作,來判斷資源是否可以訪問。 顧名思義,加鎖(lock)後,別人就無法開啟,只有當鎖沒有關閉(unlock)的時候才能訪問資源。 即物件互斥鎖的概念,來保證共享資料操作的完整性。每個物件都對應於一個可稱為” 互斥鎖” 的標記, 這個標記用來保證在任一時刻,只能有一個執行緒訪問該物件。

引數一 建立一個鎖 引數二指定了新建互斥鎖的屬性。如果引數attr為NULL,則使用預設的互斥鎖屬性,預設屬性為快速互斥鎖

  • PTHREAD_MUTEX_TIMED_NP,這是預設值,也就是普通鎖。當一個執行緒加鎖以後,其餘請求鎖的執行緒將形成一個等待佇列,並在解鎖後按優先順序獲得鎖。這種鎖策略保證了資源分配的公平性。
  • PTHREAD_MUTEX_RECURSIVE_NP,巢狀鎖,允許同一個執行緒對同一個鎖成功獲得多次,並通過多次unlock解鎖。如果是不同執行緒請求,則在加鎖執行緒解鎖時重新競爭。
  • PTHREAD_MUTEX_ERRORCHECK_NP,檢錯鎖,如果同一個執行緒請求同一個鎖,則返回EDEADLK,否則與PTHREAD_MUTEX_TIMED_NP型別動作相同。這樣就保證當不允許多次加鎖時不會出現最簡單情況下的死鎖。
  • PTHREAD_MUTEX_ADAPTIVE_NP,適應鎖,動作最簡單的鎖型別,僅等待解鎖後重新競爭。

程式碼:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
int i=0;
//鎖物件
pthread_mutex_t mutex;
void* thr_fun(void* arg){

        char* no = (char*)arg;
       //加鎖的程式碼塊
        pthread_mutex_lock(&mutex);
        for(; i < 10; i++){
                printf("%s thread, i:%d\n",no,i);
               sleep(1);
        }
        //取消鎖
        pthread_mutex_unlock(&mutex);
        i=0;
        return 1;
}


void main(){
        //互斥鎖的初始化        
        pthread_mutex_init(&mutex,NULL);
        //執行緒初始化
        pthread_t tid1,tid2;
        pthread_create(&tid1,NULL,thr_fun,"執行緒1");
        pthread_create(&tid2,NULL,thr_fun,"執行緒2");

        void *rval;
        pthread_join(tid1,&rval);
        pthread_join(tid2,&rval);
        printf("執行緒結束%d\n",rval);
        //銷燬鎖
        pthread_mutex_destroy(&mutex);
}

列印結果:

[[email protected] threadDemo]# gcc 02.c -o main2 -lpthread
02.c: In function ‘thr_fun’:
02.c:20: warning: return makes pointer from integer without a cast
[[email protected] threadDemo]# ls
02.c  main  main2  test1.c  thread01.c
[[email protected] threadDemo]# ./main2
執行緒2 thread, i:0
執行緒2 thread, i:1
執行緒2 thread, i:2
執行緒2 thread, i:3
執行緒2 thread, i:4
執行緒2 thread, i:5
執行緒2 thread, i:6
執行緒2 thread, i:7
執行緒2 thread, i:8
執行緒2 thread, i:9
執行緒1 thread, i:0
執行緒1 thread, i:1
執行緒1 thread, i:2
執行緒1 thread, i:3
執行緒1 thread, i:4
執行緒1 thread, i:5
執行緒1 thread, i:6
執行緒1 thread, i:7
執行緒1 thread, i:8
執行緒1 thread, i:9
執行緒結束1

可以看到 先列印了執行緒二執行的輸入 結束之後才打印執行緒一的輸出.

生產者消費者

阻塞在條件變數上pthread_cond_wait

解除在條件變數上的阻塞pthread_cond_signal

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

//模擬 產品佇列
int ready = 0;

//互斥鎖
pthread_mutex_t mutex;

//條件變數 判斷是否有產品
pthread_cond_t has_product;

//生產者
void* produce(void *arg){
        char* name = (char*)arg;
        for(;;) {
                //鎖住
                pthread_mutex_lock(&mutex);
                ready++;//生產進入佇列
                printf("%s  生產 %d \n",name,ready);
                //傳送一條解鎖訊息
                pthread_cond_signal(&has_product);
                //解鎖
                pthread_mutex_unlock(&mutex);
                sleep(3);
        }
}

//消費者
void* consumer(void* arg){
        char* name = (char*)arg;
        for(;;){
                //加鎖
                pthread_mutex_lock(&mutex);
                //如果產品列表為空 繼續等待, 因為有可能不止一個消費者
                while(ready==0){
                        printf("沒有產品了,等待生產\n");
                        //等待
                        pthread_cond_wait(&has_product,&mutex);
                }
                //消費 出佇列
                printf("%s 消費%d\n",name,ready);
                ready--;
                printf(" 當前產品%d\n",ready);
                //解鎖
                pthread_mutex_unlock(&mutex);
                sleep(1);
        }
}

void main(){
        //互斥鎖初始化
        pthread_mutex_init(&mutex,NULL);
        //條件變數初始化
        pthread_cond_init(&has_product,NULL);
        //執行緒的引用 這裡三個 一個生產兩個消費
        pthread_t tid1,tid2,tid3;
        pthread_create(&tid1,NULL,produce,"生產者1");
        pthread_create(&tid2,NULL,consumer,"消費者1");
        pthread_create(&tid3,NULL,consumer,"消費者2");

        printf("開啟執行緒");
        void *rval;
        pthread_join(tid1,&rval);
        pthread_join(tid2,&rval);
        pthread_join(tid3,&rval);
        printf("執行緒結束%d\n",rval);
}


結果:

開啟執行緒沒有產品了,等待生產
沒有產品了,等待生產
生產者1  生產 1 
消費者2 消費1
 當前產品0
沒有產品了,等待生產
生產者1  生產 1 
消費者1 消費1
 當前產品0
沒有產品了,等待生產
生產者1  生產 1 
消費者2 消費1
 當前產品0
沒有產品了,等待生產
生產者1  生產 1 
消費者1 消費1
 當前產品0
沒有產品了,等待生產
生產者1  生產 1 
消費者2 消費1
 當前產品0
沒有產品了,等待生產
生產者1  生產 1 
消費者1 消費1
 當前產品0
沒有產品了,等待生產

生產者消費者模式.