posix thread 浅谈
用Posix thread进行多线程设计,就不怕跨平台了,因为很多OS都兼容Posix thread,如Linux/Windows等,甚至嵌入式系统上(如rt-thread)都支持posix thread API。线程有比进程体积小,速率高,速度快等优势。所以编程时,如果涉及到效率和速度时,采用pthread_create()一个线程总比 fork()一个进程好些。
Posxi thread 线程操作主要有创建(creation),终止(termination),同步(joins,blocking),调度(scheduling),数据管理(datamanagement)和交互(interaction).
可以从以下线程框图了解线程的构架:
多线程间关系:
多线程间共享内存模型:
与普通的fork()进程不一样,线程很简单,线程并不需要维护线程列表,也不需要知道谁创建了它。以下是pthread_create()与fork()在各种平台上,性能的比较:
- The primary motivation for using Pthreads is to realize potential program performance gains.
- When
compared to the cost of creating and managing a process, a thread can
be created with much less operating system overhead. Managing threads
requires fewer system resources than managing processes.
For example, the following table compares timingresults for the fork() subroutineand the pthread_create() subroutine.Timings reflect 50,000 process/thread creations, were performed with the time utility, and units are in
seconds, nooptimization flags.
Note: don't expect the sytem and user times toadd up to real time,
because these are SMP systems with multiple CPUs workingon the problem
at the same time. At best, these are approximations run on
localmachines, past and present.
Platform |
fork() |
pthread_create() |
||||
real |
user |
sys |
real |
user |
sys |
|
Intel 2.8 GHz Xeon 5660 (12cpus/node) |
4.4 |
0.4 |
4.3 |
0.7 |
0.2 |
0.5 |
AMD 2.3 GHz Opteron (16cpus/node) |
12.5 |
1.0 |
12.5 |
1.2 |
0.2 |
1.3 |
AMD 2.4 GHz Opteron (8cpus/node) |
17.6 |
2.2 |
15.7 |
1.4 |
0.3 |
1.3 |
IBM 4.0 GHz POWER6 (8cpus/node) |
9.5 |
0.6 |
8.8 |
1.6 |
0.1 |
0.4 |
IBM 1.9 GHz POWER5 p5-575 (8cpus/node) |
64.2 |
30.7 |
27.6 |
1.7 |
0.6 |
1.1 |
IBM 1.5 GHz POWER4 (8cpus/node) |
104.5 |
48.6 |
47.2 |
2.1 |
1.0 |
1.5 |
INTEL 2.4 GHz Xeon (2 cpus/node) |
54.9 |
1.5 |
20.8 |
1.6 |
0.7 |
0.9 |
INTEL 1.4 GHz Itanium2 (4 cpus/node) |
54.5 |
1.1 |
22.2 |
2.0 |
1.2 |
0.6 |
在同一个线程或进程中所创建的线程共同享有一样的地址空间。
线程间共享:
.进程指令(process instructions)
.大部分数据(most data)
.文件(descriptors)
.信号和信号句柄(signals and signal handlers)
.当前工作目录(current working directory)
.用户和组id(user and group id)
线程独自属性:
.线程id(thread id)
.寄存器(内容)和栈不同(set of registers,stack pointer)
.局部变量,返回地址(stack for local variables,return addresses)
.信号mask(signal mask)
.优先级(priority)
.返回值(return value errno)
主要的操作函数:
/*创建一个线程,成功返回0,失败返回error错误标志*/
- int pthread_create(pthread_t * thread, //thread :线程id, unsigned long intxi型
- const pthread_attr_t *attr, //attr: 线程属性参数,创建时将根据这个参数进行线程初始化
- void *(*start_routine)(void *), //start_routine:指向线程所调用的函数
- void *arg); //arg :线程传递参数
/* 终止线程,成功返回0,失败返回error错误 标志*/
- void pthread_exit(void *retval); //retval:返回值指针
/*等待直到id为th线程运行结束(合并一个线程的意思)*/
- int pthread_join(pthread_t th, void**thread_return); // th:线程id
- // thread_return :线程终止或取消时的返回值指针
/*获取当前线程id*/
- pthread_t pthread_self(void);
线程的同步机制:
.互斥量(mutexes)
.连接/合并(joins)
.条件变量(condition variables)
/*线程间互斥量操作函数,顾名思义*/
- int pthread_mutex_lock(pthread_mutex_t*mutex);//获取mutex,成功返0,失败返回错误标志,并阻塞当前线程
- intpthread_mutex_trylock(pthread_mutex_t *mutex); //同上,不同的是多了个try(也就是说先try一下)
- //如果在当前线程中,如果同一个互斥量已经被当前线程锁住,pthread_mutex_tyrlock将立即返回(成功).如果互斥量类型为:PTHREAD_MUTEX_RECURSIVE那么mutexlock count将自加一,然后立即返回(成功)
- int pthread_mutex_unlock(pthread_mutex_t*mutex); //释放一个mutex
实现原理:互斥量用于多线程对临界资源的访问,通过mutex lock
count来判定是否锁住,初始值为0,当pthread_mutex_lock时mutex lock_count
自加,pthread_mutex_unlock时将mutex_lock_count自减。所以互斥量可用时mutex_lock_count =
0,对于一个临界资源,使用前应先lock,使用完后再unlock,如果使用不当,会有意外发生,但如果先unlock那么
mutex_lock_count 自减1,说明改互斥量将可以同时使用2次了。
条件变量操作函数:
/*初始化一个条件变量cond(布尔型),成功返回0,失败返回error错误标志*/
- int pthread_cond_init(pthread_cond_t *restrictcond,
- const pthread_condattr_t*restrict attr);
/*销毁一个条件变量cond,成功返回0,失败返回error错误标志*/
- int pthread_cond_destroy(pthread_cond_t*cond);
/*释放一个互斥量且等待(即阻塞当前线程)一个条件变量cond为真,后再lock*/
- <pre name="code" class="cpp"> int pthread_cond_timedwait(pthread_cond_t*restrict cond, pthread_mutex_t *restrict mutex,
- const struct timespec *restrictabstime);//等待条件变量cond是否为真,时限为abstime
- int pthread_cond_wait(pthread_cond_t*restrict cond,
- pthread_mutex_t *restrict mutex); //等待条件cond是否为真,时限为cond真为止</pre>
- <pre></pre>
- <p></p>
- <p>/*释放条件变量cond,唤醒先前已被阻塞的线程*/ </p>
- <p></p>
- <pre name="code" class="cpp"> intpthread_cond_broadcast(pthread_cond_t *cond);//唤醒所有因条件变量cond而阻塞的线程
- intpthread_cond_signal(pthread_cond_t *cond);//
唤醒一个因条件变量cond而阻塞的线程</pre><pre name="code" class="cpp"><p&
gt;<span style="font-size:10px;"></span></p></pre> - <p></p>
- <p>编程实例:</p>
- <p>
完成一个有趣的游戏(类似抢板凳):主线程中创建线程1,然后线程1再创建2个线程2,3,线程2,3分别对一个计数器操作counter(初值为0),
线程1每使用一次加3,线程2每使用一次加5,如果加到被15整除,那么counter加8,看哪个线程先加到9999,并计算自己使用了多少次计算器。
先到者胜利,并打印出相应信息。</p> - <p>实现代码:</p>
- <p></p>
- <pre name="code" class="cpp">#include<pthread.h>
- #include<stdlib.h>
- #include<unistd.h>
- #include<stdio.h>
- #defineCOUNTER_MAX 9999
- static intCOUNTER;
- struct RESULT {
- pthread_t tid;
- int cnt1;
- int cnt2;
- };
- static structRESULT res;
- staticpthread_mutex_t mux = PTHREAD_MUTEX_INITIALIZER;
- staticpthread_cond_t cond =PTHREAD_COND_INITIALIZER;
- static void *thread2(void *arg)
- {
- int ret;
- printf("enter thread2, tid =%lu\n",pthread_self());
- sleep(1);
- for (;;) {
- pthread_mutex_lock(&mux);
- if(COUNTER >= COUNTER_MAX) {
- ret = pthread_cond_signal(&cond); //唤醒一个因条件变量cond而阻塞的线程
- if (ret) printf("error in thread2\n");
- res.tid = pthread_self();
- pthread_mutex_unlock(&mux); //释放mux
- pthread_exit(0);
- }
- printf(".");
- fflush(stdout);
- COUNTER += 3;
- if(COUNTER%15 == 0 && COUNTER) {
- COUNTER += 8;
- usleep(50*res.cnt1);
- }
- res.cnt1++;
- pthread_mutex_unlock(&mux);
- usleep(COUNTER);
- }
- }
- static void *thread3(void *arg)
- {
- int ret;
- printf("enter thread3, tid =%lu\n",pthread_self());
- sleep(1);
- for (;;) {
- pthread_mutex_lock(&mux);
- if(COUNTER >= COUNTER_MAX) {
- ret = pthread_cond_signal(&cond); //唤醒一个因条件变量cond而阻塞的线程
- if (ret) printf("error in thread3\n");
- res.tid = pthread_self();
- pthread_mutex_unlock(&mux); //释放mux
- pthread_exit(0);
- }
- printf("o");
- fflush(stdout);
- COUNTER += 5;
- if(COUNTER%15 == 0 && COUNTER) {
- COUNTER += 8;
- usleep(50*res.cnt2);
- }
- res.cnt2++;
- pthread_mutex_unlock(&mux);
- usleep(COUNTER);
- }
- }
- static void *thread1(void *arg)
- {
- int ret;
- pthread_t tid2,tid3;
- printf("starting...\n");
- pthread_mutex_lock(&mux);
- ret =pthread_create(&tid2,NULL,thread2,NULL);
- if (ret) {
- printf("create thread1 error\n");
- }
- ret =pthread_create(&tid3,NULL,thread3,NULL);
- if (ret) {
- printf("create thread2 error\n");
- }
- pthread_cond_wait(&cond,&mux); //释放mux,等待cond为真
- if (res.tid == tid2) {
- pthread_cancel(tid2);
- }
- else {
- pthread_cancel(tid3);
- }
- printf("\nget the winner:\n%s, tid= %lu,",(res.tid==tid2?"thread2":"thread3"),res.tid);
- printf("cnt1 = %d,cnt2 =%d\n",res.cnt1,res.cnt2);
- pthread_mutex_unlock(&mux);
- pthread_exit(0);
- }
- int main(void)
- {
- int ret;
- pthread_t tid1;
- ret =pthread_create(&tid1,NULL,thread1,NULL);
- if (ret) {
- printf("create thread1 error\n");
- }
- if (pthread_join(tid1,NULL)) { //等待thread1结束
- printf("error in thread1\n");
- }
- exit(0);
- }</pre>
- <p></p>
- <p>测试结果:</p>
- <p></p>
- <pre name="code" class="cpp">starting...
- enter thread3, tid= 3062217584
- enter thread2, tid= 3070610288
- o..o.o.o.o.o.o.o.o.oo..oo..o.o.o..oo..oo..o.o.o..oo..oo.o.o.o.o.o.o.o.o.o..oo..oo.o.o.o.o.o.o.o..oo.o..oo..o.o.o.o.o.o.o..o.oo.o.oo..oo.o.o.o.oo.o.o.o.o.o.o.o.o.o.o..o.oo.o.o.oo.o.o.o.o.o.o.o.o.o.o.o..oo..o.o..oo.o.o.o..o.o.o..o.o.o.o.oo.o.o.oo.o.o.o.o.o.o.o.o.o..o.oo..oo.o.oo.o..o.o.o.o..o.oo.o..o.o.o.o.o..o.oo.o.o.o.o.oo.o.o.oo.o.o.oo..oo.o.oo.o..o.o.o.o..o.oo..o.o.o.o..o.o.o.oo.o.oo.o.o.o.oo..oo.o.o.oo.o.o.oo..o.o.o.o..o.o.oo.o.o.o.oo..o.o..o.o.o.oo.o.o.oo.o..o.o..o.o.oo.o.o.o.oo.o..o.o.o..o.oo..o.o.o..o.o.o.o.oo.o.o.oo.o.o.o.o.oo.o.oo.o.o.o.oo.o.o.o.o.oo.o.o.oo.o..o.o..o.o.o.o.oo.o.o.oo.o.o.o.oo..o.o.o..o.oo.o.o.o.oo.o.o.o.oo.o.o.o.o.o.oo.o.o.oo.o.o.o.oo.o.o.o.oo.o.o.oo.o.o.o.oo.o.o.o.o.o.o.o.o.o..o.o.o.o.o.o..o.o.o.oo.o.o.oo.o.o.o.o.o.oo.o.o.oo.o.o.o.oo.o.o.o.oo.o.o.oo.o.o.o.o.o.o.o.o.o.o..o.oo.o..o.o.o.o.o..o.oo.o.o.o.oo.o.o.o.oo.o.o.o.o.oo.o.o.o.o.o.o.o.o.o..o.o.oo.o.o.oo.o.o.o.oo.o.o.o.oo.o.o.o.oo.o.o.o.oo.o.o.o.oo.o.o.oo.o..o.o.o..o.o.oo.o.o.o.o.oo.o.o.o.o.o.o.o.o..o.o.o.o.o.o.o..o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.oo.o.o.o.o.o.o.o.o.o.o.o.o..o.o.o.o.o..o.o.o.o.o.o.o.o.o.o.o.o.o.oo.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o..o.o.o.o.o.o.o..o.o..o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o..o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.oo.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o
- get the winner:
- thread2, tid =3070610288,cnt1 = 1046,cnt2 = 1072</pre>
- <p></p>
- <p style="margin-bottom:0cm" align="LEFT"><br>
- </p>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
转载自:http://blog.csdn.net/yyplc====
posix thread 浅谈的更多相关文章
- 浅谈POSIX线程的私有数据
当线程中的一个函数需要创建私有数据时,该私有数据在对函数的调用之间保持一致,数据能静态地分配在存储器中,当我们采用命名范围也许可以实现它使用在函数或是文件(静态),或是全局(EXTERN).但是当涉及 ...
- 浅谈Java的throw与throws
转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...
- 浅谈Linux中的信号处理机制(二)
首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...
- Android性能优化的浅谈
一.概要: 本文主要以Android的渲染机制.UI优化.多线程的处理.缓存处理.电量优化以及代码规范等几方面来简述Android的性能优化 二.渲染机制的优化: 大多数用户感知到的卡顿等性能问题的最 ...
- 浅谈线程池(中):独立线程池的作用及IO线程池
原文地址:http://blog.zhaojie.me/2009/07/thread-pool-2-dedicate-pool-and-io-pool.html 在上一篇文章中,我们简单讨论了线程池的 ...
- 浅谈线程池(上):线程池的作用及CLR线程池
原文地址:http://blog.zhaojie.me/2009/07/thread-pool-1-the-goal-and-the-clr-thread-pool.html 线程池是一个重要的概念. ...
- 安装JDK后JRE与JVM联系浅谈
转自安装JDK后JRE与JVM联系浅谈 安装JDK后JRE.JVM之间的关系是什么呢?那么我们要从安装JDK慢慢说起. 如果安装了JDK,会发同你的电脑有两套JRE: 一套位于 <JDK安装目录 ...
- 【转】浅谈Java中的hashcode方法(这个demo可以多看看)
浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native i ...
- 浅谈qmake之pro、pri、prf、prl文件
浅谈qmake之pro.pri.prf.prl文件 转载自:http://blog.csdn.net/dbzhang800/article/details/6348432 尽管每次和cmake对比起来 ...
随机推荐
- mysql_DML_delete
delete from 表名 删除表里的数据 可以配合where试用
- Kinect For Windows V2开发日志四:使用OpenCV显示深度图像
代码示例: #include <Kinect.h> #include <iostream> #include <opencv2\highgui.hpp> using ...
- 数组去重算法,quickSort
function removeRepeat(arr) { var arr2 = [] ,obj = {}; for (var i = 0; i<arr.length; i++) { var nu ...
- (转)Android之自定义适配器
ListView作为一个实际开发中使用率非常高的视图,一般的系统自带的适配器都无法满足开发中的需求,这时候就需要开发人员来自定义适配器使得ListView能够有一个不错的显示效果. 有这样一个Demo ...
- SQL Server 2008R2 禁用远程连接
很多人在开发过程中都会用多数据库(这里仅讨论MSSQL),也都会在服务器上装MSSQL,在你装上MSSQL后,机器上的1433端口就被激活了.如果你的服务器是在内网,也许不用过多的关注,如果你的服务器 ...
- Cocos2d-JS特效
Cocos2d-JS提供了很多特效,这些特效事实上属于间隔动作,特效类cc.GridAction类,也称为网格动作,它的类图如下图所示. 网格动作类图 网格动作cc.GridAction它有两个主要的 ...
- 【学习笔记】【C语言】数组
1. 什么是数组 数组,从字面上看,就是一组数据的意思,没错,数组就是用来存储一组数据的 2. 数组的特点 只能存放一种类型的数据,比如int类型的数组.float类型的数组 里面存放的数据称为“元素 ...
- linux工程管理工具make入门
一.make工具的功能 1.主要负责一个软件工程中多个源代码的自动编译工作 2.还能进行环境检测.后期处理等工作: 3.make工具可以识别出工程中哪些文件已经被修改,并且在再次编译的时候只编译这些文 ...
- 使用DbVisualizer 8 连接Oracle数据库
1. 网上下载一个驱动包ojdbc14.jar,放到oracle目录下:...\DbVisualizer-8.0.1\jdbc\oracle\ojdbc14.jar 2. 打开 DbVisualize ...
- C++ 双链表基本操作
上一篇博客主要总结了单向链表,这次再总结一下双向链表. 1.概念 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱.所以,从双向链表中的任意一个结点开始,都 ...