【并行计算4】Pthread实训

mac2025-12-03  12

1、基本知识

pthread.h头文件的引入 pthread_create创建线程 pthread_exit终止线程

创建进程 int pthread_create(pthread_t * thread, const pthread_attr_t * attr, void * (*start_routine)(void *), void *arg); 参数: thread - 指向线程的指针。 attr - 指向线程属性的指针。可设置为NULL。 start_routine - 用于线程化的函数指针--》是要将函数放到多个线程进行运作 arg - 指向函数参数的指针。-》指明函数的参数 返回值:线程标识id 退出进程 void pthread_exit(void *retval); 参数: retval - 指向线程返回值的指针

-EG:举例说明

#include <pthread.h> #include <stdio.h> #include <stdlib.h> #define NUM_THREADS 4 void *PrintHello(void *null) { printf("Hello World!\n"); pthread_exit(NULL); } int main (int argc, char *argv[]) { //pthread_t是建立线程相当于 pthread_t threads[NUM_THREADS]; int rc=-1, t; for(t=0; t<NUM_THREADS; t++){ printf("In main: creating thread %d\n", t); //your code here rc = pthread_create(&threads[t], NULL, PrintHello, NULL); //end of your code if (rc){ printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); } } pthread_exit(NULL); } 指明多线程运作的参数传递 rc = pthread_create(&threads[t], NULL, PrintHello, (void *)id); 函数多传递值在参数中 rc = pthread_create(&threads[t], NULL, PrintHello, (void *)thread_data_array[t]);

2、获取调用线程标识号

pthread_t pthread_self(void); 返回调用线程标识号,返回类型为pthread_t pid_t pid;//定义进程id编号 pid=getpid();//可通过get方式得到对应的pid pthread_t tid; //定义线程id编号 tid=pthread_self(); //可通过自身获取线程id值

3、比较线程标识号

//判断线程是否相等的方法 int pthread_equal(pthread_t t1, pthread_t t2); t = pthread_equal(thread_id,pthread_self()); //如果相等则返回true;不相等则返回false

4、一次初始化

在多线程环境中,有些事仅需要执行一次。通常当初始化应用程序时,可以比较容易地将其放在main函数中。但当你写一个库时,就不能在main里面初始化了,你可以用静态初始化,但使用一次初始化(pthread_once)会比较容易些。

需要注意的是: 在多线程编程环境下,尽管pthread_once()调用会出现在多个线程中,init_routine()函数仅执行一次,究竟在哪个线程中执行是不定的,是由内核调度来决定。

int pthread_once(pthread_once_t *once_control, void (*init_routine) (void)); //建立control pthread_once_t once = PTHREAD_ONCE_INIT; //init_routine函数 void once_run(void) { printf("once_run in thread %u\n", (unsigned int)pthread_self()); } //第二个参数其实就是只运作一次的函数 pthread_once(&once,once_run);

不管有几个线程或者说有几个线程获得该数据,但是只有一个线程进行运作。

5、线程取消

pthread_cancel 调用并不等待线程终止 ,它只提出请求。线程在取消请求 (pthread_cancel) 发出后会继续运行。 线程得取消是一个异步的操作

int pthread_cancel(pthread_t thread);

6、发送sig信号

pthread_kill 发送sig信号 向指定ID的线程发送一个信号,只是大部分信号的默认动作都是终止进程操作。 如果线程不处理该信号,则按照信号默认的行为作用于整个进程。 信号值0为保留信号,作用是根据函数的返回值判断线程是不是还活着。 pthread_kill的返回值:成功(0) 线程不存在(ESRCH) 信号不合法(EINVAL)

int pthread_kill(pthread_t thread, int sig);

7、线程属性-线程连接和分离

pthread_join主线程挂起直至目标进程返回pthread_attr_init初始化属性对象pthread_attr_destroy销毁属性对象pthread_attr_setdetachstate设置属性对象的分离状态

当一个线程被创建,它有一个属性定义了它是可连接的(joinable) 还是 分离的(detached)。只有是可连接的线程才能被连接(joined),若果创建的线程是分离的,则不能连接。 pthread_join函数阻塞主线程直到指定的线程终止。“连接” 是一种在线程间完成同步的方法。 pthread_detach函数 可以显式用于分离线程。

使用pthread_create的attr参数可以显式的创建可连接或分离的线程,典型四步如下:

声明一个pthread_attr_t数据类型的线程属性变量 用pthread_attr_init初始化该属性变量 用pthread_attr_setdetachstate设置可分离状态属性 完了后,用pthread_attr_destroy释放属性所占用的库资源

1、主线程挂起直至目标进程返回

int pthread_join(pthread_t thread, void **retval); 参数: thread - 线程id,标识唯一线程。 retval - 用户定义的指针,用来存储被等待线程的返回值。 返回值:0代表成功。若失败,返回的则是错误号。

2、初始化属性对象

int pthread_attr_init(pthread_attr_t *attr);

3、销毁属性对象

int pthread_attr_destroy(pthread_attr_t *attr); 参数: attr - 指向线程属性对象的指针。 返回值:0代表成功。若失败,返回的则是错误号。

4、设置属性对象的分离状态 设置可分离(PTHREAD_CREATE_DETACHED)或可连接属性(PTHREAD_CREATE_JOINABLE)。

int pthread_attr_setdetachstate(const pthread_attr_t *attr, int *detachstate); 参数: attr - 指向线程属性对象的指针。 detachstate - 设置可分离(PTHREAD_CREATE_DETACHED)或可连接属性(PTHREAD_CREATE_JOINABLE)

一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL。如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。

通常情况下,若**创建一个线程不关心它的返回值,也不想使用pthread_join来回收资源(调用pthread_join的进程会阻塞),**就可以使用pthread_detach,将该线程的状态设置为分离态,使线程结束后,立即被系统回收。 **主线程退出了,“分离线程”还是一样退出。**只是“分离线程”的资源是有系统回收的。

5、设置线程的分离态

int pthread_detach(pthread_t tid); pthread_t tid:  分离线程的tid 返回值:成功返回0,失败返回错误号。
最新回复(0)