其他分享
首页 > 其他分享> > 20191325学习笔记7

20191325学习笔记7

作者:互联网

第4章 并发编程

教材学习内容总结

本章论述了并发编程,介绍了并行计算的概念,指岀了并行计算的重要性;比较了顺序 算法与并行算法,以及并行性与并发性;解释了线程的原理及其相对于进程的优势;通过示 例介绍了 Pthread中的线程操作,包括线程管理函数,互斥量、连接、条件变量和屏障等线 程同步工具;通过具体示例演示了如何使用线程进行并发编程,包括矩阵计算、快速排序和 用并发线程求解线性方程组等方法;解释了死锁问题,并说明了如何防止并发程序中的死锁 问题;讨论了信号量,并论证了它们相对于条件变量的优点;还解释了支持Linux中线程的 独特方式。

1 并行

1、顺序算法和并行算法

2、并行性与并发性

通常,并行算法只识别可并行执行的任务,但是它没有规定如何将任务映射到处理组件。在理想情况下,并行算法中的所有任务都应该同时实时执行。然而,真正的并行执行只能在有多个处理组件的系统中实现,比如多处理器或多核系统。在单 CPU 系统中,一次只能执行一个任务。在这种情况下,不同的任务只能并发执行、即在逻辑上并行执行。在单CPU系统中,并发性是通过多任务处理来实现的。

2 线程

1、原理

2、优点

  1. 线程创建和切换速度更快。
  2. 线程的响应速度更快。
  3. 线程更适合并行计算。

3、缺点

  1. 由于地址空间共享,线程需要来自用户的明确同步。
  2. 许多库函数可能对线程不安全。
  3. 在单CPU系统上,使用线程解决问题实际上要比使用顺序程序慢,这是由在运行 时创建线程和切换上下文的系统开销造成的。

3 线程管理函数

1、创建线程

使用pthread_create()函数创建线程

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

2、线程ID

使用pthread_equal()函数对线程ID进行比较

int pthread_equal(pthread_t t1,pthread_t t2);
返回值:不同线程返回0,否则返回非0

3、线程终止

线程可以调用函数进行终止

void pthread_exit(void *status);
返回值:0退出值表示正常终止,非0值表示异常终止

4、线程连接

一个线程可以等待另一个线程的终止,通过函数终止线程的退出状态。

int pthread_join (pthread_t thread, void **status ptr);
返回值:以status_ptr返回

4、线程同步

同步是一种机制和规则,用于确保共享数据对象的完整性和并发执行肢体的协调性。

1、互斥量

最简单的同步工具时锁,它允许执行实体仅在有锁的情况下才能继续执行。在Pthread中,锁被称为互斥量。在使用前必须对他们进行初始化。

(1)静态方法

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

定义互斥量m,并使用默认属性对其进行初始化。

(2)动态方法

pthread_mutex_init(pthread_mutex_t *m,pthread_mutexattr_t,*attr);

通常attr参数可以设置位NULL,作为默认属性。

初始化完成后,线程可以通过以下函数使用互斥量。

线程使用互斥量来保护共享数据对象。

互斥量的典型用法

线程先创建一个互斥量并对它进行依次初始化。新创建的互斥量处于解锁状态,没有所有者。每个线程都试图访问一个共享数据对象:

只有获取了互斥量的线程才能访问共享数据对象。

2、死锁预防

互斥量使用封锁协议。有多种方法可以解决可能的死锁问题,其中包括死锁防御、死锁规避、死锁检测和回复等。在实际情况中,唯一可行的方法时死锁预防,试图在设计并行算法是防止死锁发生。

一种简单的死锁预防时对互斥量进行排序,并确保每个线程只在一个方向请求互斥量,这样请求序列中就不会有循环。

条件加锁和退避预防死锁

3、条件变量

作为锁,互斥量仅用于确保线程只能互斥地访问临界区中的共享数据对象。条件变量提供了一种线程协作的方法。在Pthread中,使用othread_cond_t来声明条件变量,而且必须在使用前进行初始化。

(1)静态方法

pthread_cond_t con = PTHREAD_COND_INITALLIZER;

(2)动态方法

使用pthread_cond_init()函数,通过attr参数设置条件变量。

4、信号量

信号量是进程同步的一般机制。(计数)信号量是一种数据结构

struct sem{

int value;

struct process *queue

}s;

最有名的信号量操作时P和V,定义见下文。

5、屏障

线程连接操作允许某线程(通常是主线程)等待其他线程终止。在某些情况下,保持线程活动会更好,但应要求他们在所有线程都达到指定同步点之前不能继续活动。在Pthreads中,可以采用屏障以及一系列屏障函数。

首先,主线程创建一个屏障对象

pthread_barrier_init(&barrier NULL,nthreads);

用屏蔽中同步线程数字对他进行初始化。然后,主线程创建工作线程来执行任务。

6、linux中的线程

与其他操作系统不同,Linux不区分进程和线程。对于Linux内核,线程只是一个与其他进程共享某些资源的进程。在Linux中,进程和线程都是由clone()系统调用创建的。

int clone(int(*fn)(void *),void *chile_stack,int flags,void *arg)

5 实践

 


 


 


   1 #include <stdio.h  2 #include <stdlib.h>

  3 #include <pthread.h>
  4 typedef struct{
  5     int upperbound;
  6     int lowerbound;
  7 }PARM;
  8 #define N 10
  9 int a[N]={5,1,6,4,7,2,9,8,0,3};// unsorted data
 10 int print(){//print current a[] contents
 11     int i;
 12     printf("[");
 13     for(i=0;i<N;i++)
 14         printf("%d ",a[i]);
 15     printf("]\n");
 16 }
 17 void *Qsort(void *aptr){
 18     PARM *ap, aleft, aright;
 19     int pivot, pivotIndex,left, right,temp;
20 int upperbound,lowerbound; 21 pthread_t me,leftThread,rightThread; 22 me = pthread_self(); 23 ap =(PARM *)aptr; 24 upperbound = ap->upperbound; 25 lowerbound = ap->lowerbound; 26 pivot = a[upperbound];//pick low pivot value 27 left = lowerbound - 1;//scan index from left s ide 28 right = upperbound;//scan index from right sid e 29 if(lowerbound >= upperbound) 30 pthread_exit (NULL); 31 while(left < right){//partition loop 32 do{left++;} while (a[left] < pivot); 33 do{right--;}while(a[right]>pivot); 34 if (left < right ) { 35 temp = a[left];a[left]=a[right];a[righ t] = temp;
36 } 37 } 38 print(); 39 pivotIndex = left;//put pivot back 40 temp = a[pivotIndex] ; 41 a[pivotIndex] = pivot; 42 a[upperbound] = temp; 43 //start the "recursive threads" 44 aleft.upperbound = pivotIndex - 1; 45 aleft.lowerbound = lowerbound; 46 aright.upperbound = upperbound; 47 aright.lowerbound = pivotIndex + 1; 48 printf("%lu: create left and right threadsln", me) ; 49 pthread_create(&leftThread,NULL,Qsort,(void * )&aleft);
50 pthread_create(&rightThread,NULL,Qsort,(void * )&aright); 51 //wait for left and right threads to finish 52 pthread_join(leftThread,NULL); 53 pthread_join(rightThread, NULL); 54 printf("%lu: joined with left & right threads\ n",me); 55 } 56 int main(int argc, char *argv[]){ 57 PARM arg; 58 int i, *array; 59 pthread_t me,thread; 60 me = pthread_self( ); 61 printf("main %lu: unsorted array = ", me); 62 print( ) ; 63 arg.upperbound = N-1; 64 arg. lowerbound = 0 ;
65 37 } 66 38 print(); 67 39 pivotIndex = left;//put pivot back 68 40 temp = a[pivotIndex] ; 69 41 a[pivotIndex] = pivot; 70 42 a[upperbound] = temp; 71 43 //start the "recursive threads" 72 44 aleft.upperbound = pivotIndex - 1; 73 45 aleft.lowerbound = lowerbound; 74 46 aright.upperbound = upperbound; 75 47 aright.lowerbound = pivotIndex + 1; 76 48 printf("%lu: create left and right threads ln", me) ; 77 49 pthread_create(&leftThread,NULL,Qsort,(voi d * )&aleft); arg.upperbound = N-1; 78 arg. lowerbound = 0 ;79 printf("main %lu create a thread to do QS\n" , me); 80 pthread_create(&thread,NULL,Qsort,(void * ) &a rg);//wait for Qs thread to finish 81 pthread_join(thread,NULL); 82 printf ("main %lu sorted array = ", me); 83 print () ; 84 }

#include <stdio.h>#include <stdlib.h>#include <pthread.h>typedefstruct{int upperbound; int lowerbound; }PARM; #define N 10int a[N]={5,1,6,4,7,2,9,8,0,3};// unsorted dataint print(){//print current a[] contentsint i; printf("["); for(i=0;i<N;i++) printf("%d ",a[i]); printf("]\n"); } void *Qsort(void *aptr){ PARM *ap, aleft, aright; int pivot, pivotIndex,left, right,temp; int upperbound,lowerbound; pthread_t me,leftThread,rightThread; me = pthread_self(); ap =(PARM *)aptr; upperbound = ap->upperbound; lowerbound = ap->lowerbound; pivot = a[upperbound];//pick low pivot value left = lowerbound - 1;//scan index from left side right = upperbound;//scan index from right sideif(lowerbound >= upperbound) pthread_exit (NULL); while(left < right){//partition loopdo{left++;} while (a[left] < pivot); do{right--;}while(a[right]>pivot); if (left < right ) { temp = a[left];a[left]=a[right];a[right] = temp; } } print(); pivotIndex = left;//put pivot back temp = a[pivotIndex] ; a[pivotIndex] = pivot; a[upperbound] = temp; //start the "recursive threads" aleft.upperbound = pivotIndex - 1; aleft.lowerbound = lowerbound; aright.upperbound = upperbound; aright.lowerbound = pivotIndex + 1; printf("%lu: create left and right threadsln", me) ; pthread_create(&leftThread,NULL,Qsort,(void * )&aleft); pthread_create(&rightThread,NULL,Qsort,(void *)&aright); //wait for left and right threads to finish pthread_join(leftThread,NULL); pthread_join(rightThread, NULL); printf("%lu: joined with left & right threads\n",me); } int main(int argc, char *argv[]){ PARM arg; int i, *array; pthread_t me,thread; me = pthread_self( ); printf("main %lu: unsorted array = ", me); print( ) ; arg.upperbound = N-1; arg. lowerbound = 0 ; printf("main %lu create a thread to do QS\n" , me); pthread_create(&thread,NULL,Qsort,(void * ) &arg);//wait for Qs thread to finish pthread_join(thread,NULL); printf ("main %lu sorted array = ", me); print () ; }

标签:lowerbound,upperbound,学习,right,线程,笔记,pthread,20191325,left
来源: https://www.cnblogs.com/2902480848sy/p/15489775.html