本文主要是介绍并行程序设计整理(三)—— Pthreads,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
共享内存程序 VS 分布式内存程序
共享内存程序
在共享内存程序中,变量可以是共享的,也可以是私有的。
共享变量可以被任何线程读写,私有变量通常只能被一个线程访问。线程之间的通信通常通过共享变量完成,因此此种方式下通信是隐式的。
动态线程
在这个范例中,通常有一个主线程,并且在任何给定时刻都有一个(可能是空的)工作线程集合。
主线程通常等待工作请求,当一个新的请求到达时,它会fork一个工作线程,该线程执行请求,当该线程完成工作时,它终止并加入主线程。
这种范例有效地利用了系统资源,因为线程所需要的资源只在线程实际运行时才会被使用。
静态线程
在这个范例中,在主线程进行任何必要的设置之后会fork出所有的线程,这些线程一直运行直到所有的工作完成。在线程加入主线程后,主线程可能会做一些清理(例如,释放内存),这样被fork出来的线程也会终止。
在资源使用方面效率较低,如果一个线程是空闲的,它的资源(例如,堆栈,程序计数器,等等)都不能被释放。
优点是,它更接近于最广泛使用的分布式内存编程范例。
线程安全
如果一个函数或库在被多个同时执行的线程调用时能够“正确”操作,那么它就是线程安全的。
由于多个线程通过共享内存进行通信和协调,因此线程安全代码会使用适当的同步来修改共享内存的状态。
Pthreads
POSIX: P ortable O perating S ystem I nterface for UNI X,是UNIX的可移植操作系统接口,提供操作系统实用程序的接口。
PThreads: POSIX线程接口。系统调用来创建和同步线程
PThreads支持创建并行性、同步,但不支持显式通信,因为共享内存是隐式的。
创建线程
pthread_create
函数用来启动线程,其签名为:
int pthread_create(pthread_t* thread_p /* out */,const pthread_attr_t* attr_p /* in */,void* (*start_routine)(void*) /* in */,void* arg_p /* in */);
参数列表:
thread_p
:指向某一个pthread_t
对象。*⚠️注意:对象不是通过调用pthread create来分配的;它必须在调用之前分配。
attr_p
:不会使用这个参数,函数调用中传递参数NULL
。
(*start_routine)(void*)
:线程要运行的函数。
arg_p
:一个指针,指向应该传递给函数start_routine
的参数。
返回值:大多数Pthreads
函数的返回值表示函数调用中是否有错误。在这个函数中,如果创建操作失败,返回值将被设置为非零(nonzero)
终止线程
主线程为某一线程调用pthread_join
函数来完成终止,函数签名为:
int pthread_join(pthread_t thread /* in */,void** ret_val_p /* out */);
thread
:代表了一个pthread_t
对象。
ret_val_p
:接收由线程计算的任何返回值。
如果将主线程视为一条线,如下图所示,那么,当调用pthread_create
时,主线程上会创建一个分支或分叉。对pthread_create
的多次调用将导致多个分支或分叉。然后,当由pthread_create
启动的线程终止时,这些分支会并入主线程。
一个例子
int main() {pthread_t threads[16];int tn;for(tn = 0; tn < 16; tn++) {pthread_create(&threads[tn], NULL, ParFun, NULL);}for(tn = 0; tn < 16; tn++) {pthread_join(threads[tn], NULL);}return 0;
}
在上面这段代码中,一共创建了 16 16 16个线程来执行函数ParFun
。
*⚠️注意:线程创建的成本很高,因此ParFun并行地做大量工作以分摊这些成本是很重要的。
关于共享数据的问题:
- 在
main
函数外声明的变量是共享的 - 在堆上分配的对象可以被共享(如需要共享可以通过指针传递)
- 堆栈上的变量是私有的:将指向这些变量的指针传递给其他线程可能会导致问题。
Hello World
书上实例:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>/* Global variable: accessible to all threads */
int thread_count;void* Hello(void* rank); /* Thread function */int main(int argc, char* argv[]) {long thread; /* Use long in case of a 64−bit system */pthread_t* thread_handles;/* Get number of threads from command line */thread_count = strtol(argv[1], NULL, 10);thread_handles = malloc (thread count*sizeof(pthread t));for (thread = 0; thread < thread_count; thread++)pthread_create(&thread handles[thread], NULL, Hello, (void*) thread);printf("Hello from the main thread\n");for (thread = 0; thread < thread_count; thread++)pthread_join(thread_handles[thread], NULL);free(thread_handles);return 0;
} /* main */
void* Hello(void* rank) {long my_rank = (long) rank;/* Use long in case of 64−bit system */printf("Hello from thread %ld of %dn\n", my_rank, thread_count);return NULL;
} /* Hello */
矩阵向量乘法
设 A = ( a i j ) A = (a_{ij}) A=(aij)是一个 m × n m\times n m×n的矩阵, x = ( x 0 , x 1 , ⋯ , x n − 1 ) T \textbf{x} = (x_0,x_1,\cdots,x_n-1)^T x=(x0,x1,⋯,xn
这篇关于并行程序设计整理(三)—— Pthreads的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!