jni中的執行緒, 同步以及生產者消費者模式
阿新 • • 發佈:2018-12-09
- 編譯環境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
沒有產品了,等待生產
生產者消費者模式.