Posix thread 多线程编程

2024-08-25 00:32
文章标签 多线程 编程 thread posix

本文主要是介绍Posix thread 多线程编程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

====本文系本站原创,欢迎转载! 转载请注明出处:http://blog.csdn.net/yyplc====

用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错误标志*/

[cpp]  view plain  copy
  1. int pthread_create(pthread_t * thread,            //thread :线程id, unsigned long intxi型  
  2.                     const pthread_attr_t *attr,       //attr: 线程属性参数,创建时将根据这个参数进行线程初始化  
  3.                     void *(*start_routine)(void *), //start_routine:指向线程所调用的函数  
  4.                     void *arg);                                //arg :线程传递参数   

/* 终止线程,成功返回0,失败返回error错误 标志*/

[cpp]  view plain  copy
  1. void pthread_exit(void *retval);      //retval:返回值指针  

  /*等待直到id为th线程运行结束(合并一个线程的意思)*/

[cpp]  view plain  copy
  1. int pthread_join(pthread_t th, void**thread_return);  // th:线程id  
  2.                                         // thread_return :线程终止或取消时的返回值指针  

/*获取当前线程id*/

[cpp]  view plain  copy
  1. pthread_t pthread_self(void);   

线程的同步机制:

.互斥量(mutexes)

.连接/合并(joins)

.条件变量(condition variables)


/*线程间互斥量操作函数,顾名思义*/

[cpp]  view plain  copy
  1. int pthread_mutex_lock(pthread_mutex_t*mutex);//获取mutex,成功返0,失败返回错误标志,并阻塞当前线程  
  2. intpthread_mutex_trylock(pthread_mutex_t *mutex); //同上,不同的是多了个try(也就是说先try一下)  
  3. //如果在当前线程中,如果同一个互斥量已经被当前线程锁住,pthread_mutex_tyrlock将立即返回(成功).如果互斥量类型为:PTHREAD_MUTEX_RECURSIVE那么mutexlock count将自加一,然后立即返回(成功)  
  4. 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错误标志*/

[cpp]  view plain  copy
  1. int pthread_cond_init(pthread_cond_t *restrictcond,     
  2.              const pthread_condattr_t*restrict attr);  

/*销毁一个条件变量cond,成功返回0,失败返回error错误标志*/

[cpp]  view plain  copy
  1. int pthread_cond_destroy(pthread_cond_t*cond);  

/*释放一个互斥量且等待(即阻塞当前线程)一个条件变量cond为真,后再lock*/ 

[cpp]  view plain  copy
  1. <pre name="code" class="cpp"int pthread_cond_timedwait(pthread_cond_t*restrict cond, pthread_mutex_t *restrict mutex,  
  2.  const struct timespec *restrictabstime);//等待条件变量cond是否为真,时限为abstime  
  3.  int pthread_cond_wait(pthread_cond_t*restrict cond,  
  4.  pthread_mutex_t *restrict mutex); //等待条件cond是否为真,时限为cond真为止</pre>  
  5. <pre></pre>  
  6. <p></p>  
  7. <p>/*释放条件变量cond,唤醒先前已被阻塞的线程*/ </p>  
  8. <p></p>  
  9. <pre name="code" class="cpp"> intpthread_cond_broadcast(pthread_cond_t *cond);//唤醒所有因条件变量cond而阻塞的线程  
  10.  intpthread_cond_signal(pthread_cond_t *cond);//唤醒一个因条件变量cond而阻塞的线程</pre><pre name="code" class="cpp"><p><span style="font-size:10px;"></span></p></pre>  
  11. <p></p>  
  12. <p>编程实例:</p>  
  13. <p>完成一个有趣的游戏(类似抢板凳):主线程中创建线程1,然后线程1再创建2个线程2,3,线程2,3分别对一个计数器操作counter(初值为0),线程1每使用一次加3,线程2每使用一次加5,如果加到被15整除,那么counter加8,看哪个线程先加到9999,并计算自己使用了多少次计算器。先到者胜利,并打印出相应信息。</p>  
  14. <p>实现代码:</p>  
  15. <p></p>  
  16. <pre name="code" class="cpp">#include<pthread.h>  
  17. #include<stdlib.h>  
  18. #include<unistd.h>  
  19. #include<stdio.h>  
  20.    
  21. #defineCOUNTER_MAX 9999  
  22. static intCOUNTER;  
  23. struct RESULT {  
  24.     pthread_t tid;  
  25.     int cnt1;  
  26.     int cnt2;  
  27. };  
  28. static structRESULT res;  
  29. staticpthread_mutex_t   mux  = PTHREAD_MUTEX_INITIALIZER;  
  30. staticpthread_cond_t    cond =PTHREAD_COND_INITIALIZER;  
  31.    
  32.    
  33. static void *thread2(void *arg)  
  34. {  
  35.     int ret;  
  36.    
  37.     printf("enter thread2, tid =%lu\n",pthread_self());  
  38.     sleep(1);  
  39.     for (;;) {  
  40.        pthread_mutex_lock(&mux);  
  41.         if(COUNTER >= COUNTER_MAX) {  
  42.            ret = pthread_cond_signal(&cond); //唤醒一个因条件变量cond而阻塞的线程  
  43.            if (ret) printf("error in thread2\n");  
  44.            res.tid = pthread_self();  
  45.            pthread_mutex_unlock(&mux); //释放mux  
  46.            pthread_exit(0);        
  47.         }  
  48.        printf(".");  
  49.        fflush(stdout);  
  50.        COUNTER += 3;  
  51.         if(COUNTER%15 == 0 && COUNTER) {  
  52.            COUNTER += 8;  
  53.            usleep(50*res.cnt1);  
  54.         }  
  55.        res.cnt1++;  
  56.        pthread_mutex_unlock(&mux);  
  57.        usleep(COUNTER);  
  58.     }  
  59. }  
  60.    
  61. static void *thread3(void *arg)  
  62. {  
  63.     int ret;  
  64.    
  65.     printf("enter thread3, tid =%lu\n",pthread_self());  
  66.     sleep(1);  
  67.     for (;;) {  
  68.        pthread_mutex_lock(&mux);  
  69.         if(COUNTER >= COUNTER_MAX) {  
  70.            ret = pthread_cond_signal(&cond); //唤醒一个因条件变量cond而阻塞的线程  
  71.            if (ret) printf("error in thread3\n");  
  72.            res.tid = pthread_self();  
  73.            pthread_mutex_unlock(&mux); //释放mux  
  74.            pthread_exit(0);  
  75.         }  
  76.        printf("o");  
  77.        fflush(stdout);  
  78.        COUNTER += 5;  
  79.         if(COUNTER%15 == 0 && COUNTER) {  
  80.            COUNTER += 8;  
  81.                 usleep(50*res.cnt2);  
  82.         }  
  83.        res.cnt2++;  
  84.        pthread_mutex_unlock(&mux);  
  85.        usleep(COUNTER);   
  86.     }  
  87. }  
  88.    
  89. static void *thread1(void *arg)  
  90. {  
  91.     int ret;  
  92.     pthread_t tid2,tid3;  
  93.         printf("starting...\n");  
  94.     pthread_mutex_lock(&mux);  
  95.     ret =pthread_create(&tid2,NULL,thread2,NULL);  
  96.     if (ret) {  
  97.        printf("create thread1 error\n");  
  98.     }  
  99.      
  100.     ret =pthread_create(&tid3,NULL,thread3,NULL);  
  101.     if (ret) {  
  102.        printf("create thread2 error\n");   
  103.     }  
  104.     pthread_cond_wait(&cond,&mux);   //释放mux,等待cond为真  
  105.     if (res.tid == tid2) {  
  106.             pthread_cancel(tid2);  
  107.     }  
  108.     else {  
  109.        pthread_cancel(tid3);  
  110.     }  
  111.         printf("\nget the winner:\n%s, tid= %lu,",(res.tid==tid2?"thread2":"thread3"),res.tid);  
  112.     printf("cnt1 = %d,cnt2 =%d\n",res.cnt1,res.cnt2);  
  113.     pthread_mutex_unlock(&mux);  
  114.     pthread_exit(0);  
  115. }  
  116.    
  117. int main(void)  
  118. {  
  119.     int ret;  
  120.     pthread_t tid1;  
  121.    
  122.     ret =pthread_create(&tid1,NULL,thread1,NULL);  
  123.     if (ret) {  
  124.        printf("create thread1 error\n");  
  125.     }  
  126.      
  127.     if (pthread_join(tid1,NULL)) { //等待thread1结束  
  128.       printf("error in thread1\n");  
  129.     }  
  130.    
  131.     exit(0);  
  132. }</pre>  
  133. <p></p>  
  134. <p>测试结果:</p>  
  135. <p></p>  
  136. <pre name="code" class="cpp">starting...  
  137. enter thread3, tid= 3062217584  
  138. enter thread2, tid= 3070610288 
  139. thread2, tid =3070610288,cnt1 = 1046,cnt2 = 1072</pre>  
  140. <p></p>  
  141. <p align="LEFT" style="margin-bottom:0cm"><br>  
  142. </p>  
  143. <pre></pre>  
  144. <pre></pre>  
  145. <pre></pre>  
  146. <pre></pre>  
  147. <pre></pre>  
  148. <pre></pre>  
  149. <pre></pre>  
  150. <pre></pre>  
  151.      

这篇关于Posix thread 多线程编程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1104047

相关文章

C#反射编程之GetConstructor()方法解读

《C#反射编程之GetConstructor()方法解读》C#中Type类的GetConstructor()方法用于获取指定类型的构造函数,该方法有多个重载版本,可以根据不同的参数获取不同特性的构造函... 目录C# GetConstructor()方法有4个重载以GetConstructor(Type[]

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念

函数式编程思想

我们经常会用到各种各样的编程思想,例如面向过程、面向对象。不过笔者在该博客简单介绍一下函数式编程思想. 如果对函数式编程思想进行概括,就是f(x) = na(x) , y=uf(x)…至于其他的编程思想,可能是y=a(x)+b(x)+c(x)…,也有可能是y=f(x)=f(x)/a + f(x)/b+f(x)/c… 面向过程的指令式编程 面向过程,简单理解就是y=a(x)+b(x)+c(x)

Thread如何划分为Warp?

1 .Thread如何划分为Warp? https://jielahou.com/code/cuda/thread-to-warp.html  Thread Index和Thread ID之间有什么关系呢?(线程架构参考这里:CUDA C++ Programming Guide (nvidia.com)open in new window) 1维的Thread Index,其Thread

多线程解析报表

假如有这样一个需求,当我们需要解析一个Excel里多个sheet的数据时,可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完之后,程序需要提示解析完成。 Way1 join import java.time.LocalTime;public class Main {public static void main(String[] args) thro

Java并发编程之——BlockingQueue(队列)

一、什么是BlockingQueue BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种: 1. 当队列满了的时候进行入队列操作2. 当队列空了的时候进行出队列操作123 因此,当一个线程试图对一个已经满了的队列进行入队列操作时,它将会被阻塞,除非有另一个线程做了出队列操作;同样,当一个线程试图对一个空