分享

linux和android端的pthread学习

 LeoSea 2015-01-12

本文起初主要想写个示例实测下pthread_mutex_lock和pthread_mutex_trylock区别。在linux机器上很快就over了,但是想了一下,pthread是unix系的,在windows没办法直接运行代码很不方便。于是想到了android,windows上安装ndk,手机root就可以跑pthread代码咯。。。

demo

lock和trylock的区别也很好理解:,前者是阻塞的,死等知道互斥锁被释放;而后者则更加灵活,浅尝辄止,做个尝试不行则干其他事情去。。测试代码pt_lock.c如下:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. #include <pthread.h>  
  5. #include <unistd.h>  
  6. #include <sys/types.h>  
  7.   
  8. typedef pthread_t pt_t;  
  9. typedef unsigned int uint_t;  
  10.   
  11. pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;  
  12.   
  13. void lock_func(void* arg)  
  14. {  
  15.     pid_t pid;  //process  
  16.     pt_t tid;   // thread  
  17.       
  18.     pid = getpid();  
  19.     tid = pthread_self();  
  20.   
  21.     printf("want to lock mutex, msg=%s, tid=%u\n", (char*)arg, (uint_t)tid);  
  22.       
  23.     pthread_mutex_lock( &mt );  
  24.     printf("I[tid=%u] am using, (*|^_^|*)\n", (uint_t)tid);  
  25.     sleep(10);  
  26.     pthread_mutex_unlock( &mt );  
  27. }  
  28.   
  29. void try_lock_func(void* arg)  
  30. {  
  31.     uint_t tid = (uint_t)pthread_self();  
  32.     int counter = 0;  
  33.       
  34.     while ( pthread_mutex_trylock( &mt ) )  
  35.     {  
  36.         sleep(1);  
  37.         ++counter;  
  38.           
  39.         printf("after sleep 1s, i [tid=%u] want to try again, iter=%d.\n", tid, counter);  
  40.     }  
  41.     printf("It is my[tid=%u] turn, so long i waited...msg=%s\n", tid, (char*)arg);  
  42.     pthread_mutex_unlock( &mt );      
  43. }  
  44.   
  45. #define XX_CREATE_FAILED(err)   \  
  46.     printf("create thread error : %s\n", strerror(err));\  
  47.     return 1;     
  48.   
  49. int main()  
  50. {  
  51.     int rc;  
  52.     pt_t pt1, pt2, pt3;  
  53.       
  54.     const char* msg1 = "block";  
  55.     const char* msg2 = "unblock";  
  56.       
  57.     rc = pthread_create(&pt1, NULL, (void*)&lock_func, (void*)msg1);    if (rc != 0)   
  58.     {  
  59.         XX_CREATE_FAILED(rc);  
  60.     }  
  61.       
  62.     rc = pthread_create(&pt2, NULL, (void*)&lock_func, (void*)msg1);    if (rc != 0)  
  63.     {  
  64.         XX_CREATE_FAILED(rc);  
  65.     }  
  66.     sleep(1);  
  67.       
  68.     rc = pthread_create(&pt3, NULL, (void*)&try_lock_func, (void*)msg2);    if (rc != 0)  
  69.     {  
  70.         XX_CREATE_FAILED(rc);  
  71.     }  
  72.       
  73.     pthread_join(pt1, NULL);  
  74.     pthread_join(pt2, NULL);  
  75.     pthread_join(pt3, NULL);      
  76.     return 0;  
  77. }  
代码思路也很好理解:创建三个线程,1和2通过lock方式去争抢mt互斥锁,3线程则灵活,每隔1秒去检测下mt互斥锁是否可以用,不会阻塞。线程1或者2占有mt的时间为10秒。

linux run

  1. xx@h10-1-152-72:~/peteryfren/cpp/pthread> gcc -Wall -o pt_lock pt_lock.c -lpthread  
  2. xx@h10-1-152-72:~/peteryfren/cpp/pthread> ./pt_lock   
输出结果与预期一致,id=1082132800线程先占有mt,10s内线程tid=1090525504阻塞,而线程tid=1098918208每隔1s测试下mt可用性。
  1. want to lock mutex, msg=block, tid=1082132800  
  2. I[tid=1082132800] am using, (*|^_^|*)  
  3. want to lock mutex, msg=block, tid=1090525504  
  4. after sleep 1s, i [tid=1098918208] want to try again, iter=1.  
  5. after sleep 1s, i [tid=1098918208] want to try again, iter=2.  
  6. after sleep 1s, i [tid=1098918208] want to try again, iter=3.  
  7. after sleep 1s, i [tid=1098918208] want to try again, iter=4.  
  8. after sleep 1s, i [tid=1098918208] want to try again, iter=5.  
  9. after sleep 1s, i [tid=1098918208] want to try again, iter=6.  
  10. after sleep 1s, i [tid=1098918208] want to try again, iter=7.  
  11. after sleep 1s, i [tid=1098918208] want to try again, iter=8.  
  12. I[tid=1090525504] am using, (*|^_^|*)  
  13. after sleep 1s, i [tid=1098918208] want to try again, iter=9.  
  14. after sleep 1s, i [tid=1098918208] want to try again, iter=10.  
  15. after sleep 1s, i [tid=1098918208] want to try again, iter=11.  
  16. after sleep 1s, i [tid=1098918208] want to try again, iter=12.  
  17. after sleep 1s, i [tid=1098918208] want to try again, iter=13.  
  18. after sleep 1s, i [tid=1098918208] want to try again, iter=14.  
  19. after sleep 1s, i [tid=1098918208] want to try again, iter=15.  
  20. after sleep 1s, i [tid=1098918208] want to try again, iter=16.  
  21. after sleep 1s, i [tid=1098918208] want to try again, iter=17.  
  22. after sleep 1s, i [tid=1098918208] want to try again, iter=18.  
  23. after sleep 1s, i [tid=1098918208] want to try again, iter=19.  
  24. It is my[tid=1098918208] turn, so long i waited...msg=unblock  

android run

android上编译和运行pt_lock参考前一篇blog:http://blog.csdn.net/ryfdizuo/article/details/28891649   具体批处理run.cmd如下:
  1. @echo "1. build .o file"  
  2.   
  3. @Rem fPIE flag is used in compiling stage.  
  4. D:\android-ndk-r9b-windows-x86\toolchains\arm-linux-androideabi-4.6\prebuilt\windows\bin\arm-linux-androideabi-gcc.exe --sysroot=D:\android-ndk-r9b-windows-x86\platforms\android-13\arch-arm -fPIE -c pt_lock.c  
  5.   
  6. @echo "2. build exec file"  
  7.   
  8. @Rem pie flag is used in linking stage.  
  9. D:\android-ndk-r9b-windows-x86\toolchains\arm-linux-androideabi-4.6\prebuilt\windows\bin\arm-linux-androideabi-gcc.exe --sysroot=D:\android-ndk-r9b-windows-x86\platforms\android-13\arch-arm -pie -o pt_lock pt_lock.o  
  10.   
  11. @pause  
里面的gcc和android系统库路径需要根据机器上实际位置修改。
注意android上gcc编译与linux上有点点差别:ndk中gcc不需要需要显式指定-lpthread。可能pthread默认就会链接。android-ndk-r9b-windows-x86\platforms\android-13\arch-arm\usr\lib目录下的这些so加载需要指定。。在Android.mk中类似。
命令行下运行run.cmd,编译pt_lock,然后推到手机上,注意我的nexus4必须是/data/local/tmp下面才有权限,运行后有错误,具体步骤:
  1. E:\GitHub\ndk_tutorial\pthread_playground>adb shell  
  2. root@mako:/ # cd /data/local/tmp  
  3. cd /data/local/tmp  
  4. root@mako:/data/local/tmp # mv /sdcard/pt_lock ./  
  5. mv /sdcard/pt_lock ./  
  6. root@mako:/data/local/tmp # chmod 751 pt_lock  
  7. chmod 751 pt_lock  
  8. root@mako:/data/local/tmp # ./pt_lock  
  9. error: only position independent executables (PIE) are supported.  
报了PIE不支持的错误,n4上安装的是android L系统,gg后知道编译的链接的需要增加pie等设置,参见[ref2],fPIE是编译时候的选项,pie是链接时候的选项,再次重新编译,推到手机上运行OK。。。pt_lock.c不需要做任何修改。

pthread学习

1.线程相关
1)回调函数类型 void* (*pfunc) (void* arg) ,参数通过void*传入,多个参数是通过结构体/数组打包。
2)线程属性,可以设置线程类型,一般是joinable,设置线程栈的大小。如果线程内部要定义大数组一定小心栈越界。
3)线程终止的几种情况:
  • 回调函数运行完成,正常退出
  • 线程内调用pthread_exit函数,不管是否完成都退出。该函数后面的所有代码都不会被执行(尤其printf等语句)。
  • 其他线程显式调用pthread_cancel 结束当前线程。
  • 整个进程被终止,因为调用了exit等函数。它下面的所有线程都被杀死,资源被回收。
  • main函数创建N个线程,两种做法等待其他线程结束:显式pthread_join等待其他线程结束;main函数中调用pthread_exit,等待其他线程结束。
2. 互斥锁相关
pthread_mutex_init
pthread_mutex_lock,阻塞等待
pthread_mutex_trylock,非阻塞等待
pthread_mutex_destroy

3. 信号量相关
pthread_mutex_init
pthread_mutex_wait 阻塞当前线程,直到满足某些条件时,伪代码如下:
begin
pthread_mutex_unlock( mutex )  阻塞之前释放互斥锁
block_on_cond( condition ) 条件阻塞
pthread_mutex_lock(mutex) 条件满足后 占有互斥锁,完成工作后需要释放互斥锁
end
该语句必须在循环中执行,而不是if中,因为线程之间可能有虚假的唤醒行为,spurious wakeup。当唤醒时需要再次确定预期的条件是否满足,如果不满足继续等待。相关的讨论参见:http:///blog/2012/07/27/pthread_cond_wait_mutex_while/

pthread_mutex_signal,只有一个线程等待时发送信号量
pthread_mutex_broadcast 多个线程同时等待时使用
pthread_mutex_destroy

4. 生存者/消费者,读写,哲学家进餐模型

refer

1. gcc下面的pie和fPIE 选项标志讲解,http://richardustc./blog/2013/05/pie/

2. android L系统下PIE错误,http://blog.csdn.net/hxdanya/article/details/39371759

3. pthread http:///linux/man-pages/man3/pthread_create.3.html


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多