在本篇文章当中讲主要给大家介绍 pthread
并发编程当中关于线程的基础概念,并且深入剖析进程的相关属性和设置,以及线程在内存当中的布局形式,帮助大家深刻理解线程。
在深入解析 pthread_create
之前,我们先用一个简单的例子简单的认识一下 pthread,我们使用 pthread 创建一个线程并且打印 Hello world 字符串。
#include <stdio.h> |
|
#include <pthread.h> |
|
void* func(void* arg) { |
|
printf("Hello World from tid = %ld\n", pthread_self()); // pthread_self 返回当前调用这个函数的线程的线程 id |
|
return NULL; |
|
} |
|
int main() { |
|
pthread_t t; // 定义一个线程 |
|
pthread_create(&t, NULL, func, NULL); // 创建线程并且执行函数 func |
|
// wait unit thread t finished |
|
pthread_join(t, NULL); // 主线程等待线程 t 执行完成然后主线程才继续往下执行 |
|
printf("thread t has finished\n"); |
|
return 0; |
|
} |
编译上述程序:
clang helloworld.c -o helloworld.out -lpthread |
|
或者 |
|
gcc helloworld.c -o helloworld.out -lpthread |
在上面的代码当中主线程(可以认为是执行主函数的线程)首先定义一个线程,然后创建线程并且执行函数 func ,当创建完成之后,主线程使用 pthread_join 阻塞自己,直到等待线程 t 执行完成之后主线程才会继续往下执行。
我们现在仔细分析一下 pthread_create
的函数签名,并且对他的参数进行详细分析:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, |
|
void *(*start_routine) (void *), void *arg); |
在下面的例子当中我们将使用 pthread_self 得到线程的 id ,并且通过保存线程 id 的地址的变量 t 得到线程的 id ,对两个得到的结果进行比较。
#include <stdio.h> |
|
#include <pthread.h> |
|
void* func(void* arg) { |
|
printf("线程自己打印线程\tid = %ld\n", pthread_self()); |
|
return NULL; |
|
} |
|
int main() { |
|
pthread_t t; |
|
pthread_create(&t, NULL, func, NULL); |
|
printf("主线程打印线程 t 的线程 id = %ld\n", *(long*)(&t)); |
|
pthread_join(t, NULL); |
|
return 0; |
|
} |
根据上面程序打印的结果我们可以知道,变量 pthread_t t
保存的就是线程 id 的地址, 参数 t 和线程 id 之间的关系如下所示:
在上面的代码当中我们首先对 t 取地址,然后将其转化为一个 long 类型的指针,然后解引用就可以得到对应地址的值了,也就是线程的ID。
在下面的程序当中我们定义了一个结构体用于保存一些字符出的信息,然后创建一个这个结构体的对象,将这个对象的指针作为参数传递给线程要执行的函数,并且在线程内部打印字符串当中的内容。
#include <stdio.h> |
|
#include <pthread.h> |
|
#include <malloc.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
typedef struct info { |
|
char s[1024]; // 保存字符信息 |
|
int size; // 保存字符串的长度 |
|
}info_t; |
|
static |
|
void* func(void* arg) { |
|
info_t* in = (info_t*)arg; |
|
in->s[in->size] = '\0'; |
|
printf("string in arg = %s\n", in->s); |
|
return NULL; |
|
} |
|
int main() { |
|
info_t* in = malloc(sizeof(info_t)); // 申请内存空间 |
|
// 保存 HelloWorld 这个字符串 并且设置字符串的长度 |
|
in->s[0] = 'H'; |
|
in->s[1] = 'e'; |
|
in->s[2] = 'l'; |
|
in->s[3] = 'l'; |
|
in->s[4] = 'o'; |
|
in->s[5] = 'W'; |
|
in->s[6] = 'o'; |
|
in->s[7] = 'r'; |
|
in->s[8] = 'l'; |
|
in->s[9] = 'd'; |
|
in->size = 10; |
|
pthread_t t; // 将 in 作为参数传递给函数 func |
|
pthread_create(&t, NULL, func, (void*)in); |
|
pthread_join(t, NULL); |
|
free(in); // 释放内存空间 |
|
return 0; |