线程按照其调度者可以分为用户级线程和核心级线程两种 
用户级线程主要解决的是上下文切换的问题,它的调度算法和调度过程全部由用户自行选择决定,在运行时不需要特定的内核支持; 
我们常用基本就是用户级线程,所以就只总结一下POSIX提供的用户级线程接口; 
基本线程操作相关的函数: 
1线程的建立结束 
2线程的互斥和同步 
3使用信号量控制线程 
4线程的基本属性配置

基本线程操作:

函数 说明
pthread_create() 创建线程开始运行相关线程函数,运行结束则线程退出
pthread_eixt() 因为exit()是用来结束进程的,所以则需要使用特定结束线程的函数
pthread_join() 挂起当前线程,用于阻塞式地等待线程结束,如果线程已结束则立即返回,0=成功
pthread_cancel() 发送终止信号给thread线程,成功返回0,但是成功并不意味着thread会终止
pthread_testcancel() 在不包含取消点,但是又需要取消点的地方创建一个取消点,以便在一个没有包含取消点的执行代码线程中响应取消请求.
pthread_setcancelstate() 设置本线程对Cancel信号的反应
pthread_setcanceltype() 设置取消状态 继续运行至下一个取消点再退出或者是立即执行取消动作
pthread_setcancel() 设置取消状态

互斥与同步机制基本函数

函数 说明
pthread_mutex_init() 互斥锁的初始化
pthread_mutex_lock() 锁定互斥锁,如果尝试锁定已经被上锁的互斥锁则阻塞至可用为止
pthread_mutex_trylock() 非阻塞的锁定互斥锁
pthread_mutex_unlock() 释放互斥锁
pthread_mutex_destory() 互斥锁销毁函数

信号量线程控制(默认无名信号量)

函数 说明
sem_init(sem) 初始化一个定位在sem的匿名信号量
sem_wait() 把信号量减1操作,如果信号量的当前值为0则进入阻塞,为原子操作
sem_trywait() 如果信号量的当前值为0则返回错误而不是阻塞调用(errno=EAGAIN),其实是sem_wait()的非阻塞版本
sem_post() 给信号量的值加1,它是一个“原子操作”,即同时对同一个信号量做加1,操作的两个线程是不会冲突的
sem_getvalue(sval) 把sem指向的信号量当前值放置在sval指向的整数上
sem_destory(sem) 销毁由sem指向的匿名信号量

线程属性配置相关函数

函数 说明
pthread_attr_init() 初始化配置一个线程对象的属性,需要用pthread_attr_destroy函数去除已有属性
pthread_attr_setscope() 设置线程属性
pthread_attr_setschedparam() 设置线程优先级
pthread_attr_getschedparam() 获取线程优先级

基本的线程建立运行pthread_create

/* thread.c */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> #define THREAD_NUMBER 3 /*线程数*/
#define REPEAT_NUMBER 5 /*每个线程中的小任务数*/
#define DELAY_TIME_LEVELS 10.0 /*小任务之间的最大时间间隔*/
//
void *thrd_func(void *arg) {
/* 线程函数例程 */
int thrd_num = (int)arg;
int delay_time = ;
int count = ;
printf("Thread %d is starting\n", thrd_num);
for (count = ; count < REPEAT_NUMBER; count++) {
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + ;
sleep(delay_time);
printf("\tThread %d: job %d delay = %d\n",
thrd_num, count, delay_time);
} printf("Thread %d finished\n", thrd_num);
pthread_exit(NULL);
} int main(void) {
pthread_t thread[THREAD_NUMBER];
int no = , res;
void * thrd_ret;
srand(time(NULL));
for (no = ; no < THREAD_NUMBER; no++) {
/* 创建多线程 */
res = pthread_create(&thread[no], NULL, thrd_func, (void*)no);
if (res != ) {
printf("Create thread %d failed\n", no);
exit(res);
}
} printf("Create treads success\n Waiting for threads to finish...\n");
for (no = ; no < THREAD_NUMBER; no++) {
/* 等待线程结束 */
res = pthread_join(thread[no], &thrd_ret);
if (!res) {
printf("Thread %d joined\n", no);
} else {
printf("Thread %d join failed\n", no);
}
}
return ;
}

例程中循环3次建立3条线程,并且使用pthread_join函数依次等待线程结束; 
线程中使用rand()获取随机值随机休眠5次,随意会出现后执行的线程先执行完成; 
运行结果:

$ gcc thread.c -lpthread
$ ./a.out
Create treads success
Waiting for threads to finish...
Thread is starting
Thread is starting
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined
Thread joined
Thread : job delay =
Thread finished
Thread joined

可以看到,线程1先于线程0执行,但是pthread_join的调用时间顺序,先等待线程0执行; 
由于线程1已经早结束,所以线程0被pthread_join等到的时候,线程1已结束,就在等待到线程1时,直接返回;

线程执行的互斥和同步pthread_mutex_lock

在上面的程序中增加互斥锁

/*thread_mutex.c*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> #define THREAD_NUMBER 3 /* 线程数 */
#define REPEAT_NUMBER 3 /* 每个线程的小任务数 */
#define DELAY_TIME_LEVELS 10.0 /*小任务之间的最大时间间隔*/
pthread_mutex_t mutex; void *thrd_func(void *arg) {
int thrd_num = (int)arg;
int delay_time = , count = ;
int res;
/* 互斥锁上锁 */
res = pthread_mutex_lock(&mutex);
if (res) {
printf("Thread %d lock failed\n", thrd_num);
pthread_exit(NULL);
}
printf("Thread %d is starting\n", thrd_num);
for (count = ; count < REPEAT_NUMBER; count++) {
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + ;
sleep(delay_time);
printf("\tThread %d: job %d delay = %d\n",
thrd_num, count, delay_time);
}
printf("Thread %d finished\n", thrd_num);
pthread_exit(NULL);
} int main(void) {
pthread_t thread[THREAD_NUMBER];
int no = , res;
void * thrd_ret; srand(time(NULL));
/* 互斥锁初始化 */
pthread_mutex_init(&mutex, NULL);
for (no = ; no < THREAD_NUMBER; no++) {
res = pthread_create(&thread[no], NULL, thrd_func, (void*)no);
if (res != ) {
printf("Create thread %d failed\n", no);
exit(res);
}
}
printf("Create treads success\n Waiting for threads to finish...\n");
for (no = ; no < THREAD_NUMBER; no++) {
res = pthread_join(thread[no], &thrd_ret);
if (!res) {
printf("Thread %d joined\n", no);
} else {
printf("Thread %d join failed\n", no);
}
}
/****互斥锁解锁***/
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
return ;
}

在上面的例程中直接添加同步锁pthread_mutex_t; 
在线程中加入,于是程序在执行线程程序时; 
调用pthread_mutex_lock上锁,发现上锁时候后进入等待,等待锁再次释放后重新上锁; 
所以线程程序加载到队列中等待,等待成功上锁后继续执行程序代码; 
运行结果

$gcc thread_mutex.c -lpthread
$ ./a.out
Create treads success
Waiting for threads to finish...
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined

跟例程1中执行结果不同,线程程序被加载到队列中而不能马上执行,需要等到能够成功上锁; 
上锁后,继续执行线程程序,上锁执行; 
这样线程被依次执行的情况在实际使用场景中经常出现; 
使用场景: 
当用户登录后获取秘钥才能继续获取该用户的基本信息时;需要等待登录线程结束后才能继续执行获取用户信息的线程时, 
需要调用两条线程,假如是:threadLogin(),threadGetInfo(); 则可以有2种方法实现: 
1 此时可以使用互斥锁同时一次性调用完threadLogin()和threadGetInfo(); 
2 当然也可以不使用互斥锁直接在threadLogin()中登录验证成功后调用threadGetInfo(); 
相比之下,方式1更加清晰的显示逻辑关系,增加代码可读性可扩展性。

使用信号量控制线程的执行顺序sem_post

修改上面例程,上面的是使用pthread_mutex_lock互斥锁控制线程执行顺序, 
使用另外一种线程执行顺序的控制;

/* thread_sem.c */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h> #define THREAD_NUMBER 3
#define REPEAT_NUMBER 3
#define DELAY_TIME_LEVELS 10.0 sem_t sem[THREAD_NUMBER]; void * thrd_func(void *arg) {
int thrd_num = (int)arg;
int delay_time = ;
int count = ;
sem_wait(&sem[thrd_num]);
printf("Thread %d is starting\n", thrd_num);
for (count = ; count < REPEAT_NUMBER; count++) {
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + ;
sleep(delay_time);
printf("\tThread %d: job %d delay = %d\n", thrd_num, count, delay_time);
}
printf("Thread %d finished\n", thrd_num);
pthread_exit(NULL);
} int main(void) {
pthread_t thread[THREAD_NUMBER];
int no = , res;
void * thrd_ret;
srand(time(NULL));
for (no = ; no < THREAD_NUMBER; no++) {
sem_init(&sem[no], , );
res = pthread_create(&thread[no], NULL, thrd_func, (void*)no);
if (res != ) {
printf("Create thread %d failed\n", no);
exit(res);
}
} printf("Create treads success\n Waiting for threads to finish...\n");
sem_post(&sem[THREAD_NUMBER - ]);
for (no = THREAD_NUMBER - ; no >= ; no--) {
res = pthread_join(thread[no], &thrd_ret);
if (!res) {
printf("Thread %d joined\n", no);
} else {
printf("Thread %d join failed\n", no);
}
sem_post(&sem[(no + THREAD_NUMBER - ) % THREAD_NUMBER]);
} for (no = ; no < THREAD_NUMBER; no++) {
sem_destroy(&sem[no]);
}
return ;
}

执行结果,仍然是建立3条线程,每条线程执行时休眠随机时长:

$ gcc thread_sem.c -lpthread
$ ./a.out
Create treads success
Waiting for threads to finish...
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined

执行结果与第2个例程非常相似,只不过教材中进行倒序执行而已; 
那么这种方式其实与使用互斥锁相比,代码量可读性基本持平不相上下;

线程的基本属性pthread_attr_setscope

设置属性一般有: 
1 绑定属性 
2 分离属性 
3 堆栈地址 
4 堆栈大小 
5 优先级

关于绑定属性就是绑定于内核线程; 
分离属性主要是讲线程结束后是否马上释放相应的内存;

/* thread_attr.c */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> #define THREAD_NUMBER 1
#define REPEAT_NUMBER 3
#define DELAY_TIME_LEVELS 10.0
int finish_flag = ; void * thrd_func(void * arg){
int delay_time = ;
int count = ;
printf("Thread is starting\n");
for (count = ; count < REPEAT_NUMBER; count++) {
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + ;
sleep(delay_time);
printf("\tThread : job %d delay = %d\n", count, delay_time);
}
printf("Thread finished\n");
finish_flag = ;
pthread_exit(NULL);
} int main(void) {
pthread_t thread;
pthread_attr_t attr;
int res = ;
srand(time(NULL));
res = pthread_attr_init(&attr);
if (res != ) {
printf("Create attribute failed\n");
exit(res);
}
res = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
res += pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (res != ) {
printf("Setting attribute failed\n");
exit(res);
}
res = pthread_create(&thread, &attr, thrd_func, NULL);
if (res != ) {
printf("Create thread failed\n");
exit(res);
}
pthread_attr_destroy(&attr);
printf("Create tread success\n"); while(!finish_flag){
printf("Waiting for thread to finish...\n");
sleep();
}
return ;
}

在运行前后使用 $ free 命令查看内存前后的使用情况发现: 
在线程结束后内存马上被释放;
其实,一般线程的属性直接使用系统默认属性即可; 
关于线程的使用,大约就是这样。

C/C++ Pthread线程的更多相关文章

  1. 【C/C++多线程编程之四】终止pthread线程

    多线程编程之终止pthread线程       Pthread是 POSIX threads 的简称,是POSIX的线程标准.           终止线程似乎是多线程编程的最后一步,但绝不是本系列教 ...

  2. [并发并行]_[线程模型]_[Pthread线程使用模型之三 客户端/服务端模型(Client/Server]

    Pthread线程使用模型之三 客户端/服务端模型(Client/Server) 场景 1.在客户端/服务端模型时,客户端向服务端请求一些数据集的操作. 服务端执行执行操作独立的(多进程或跨网络)– ...

  3. [并发并行]_[线程模型]_[Pthread线程使用模型之二 工作组work crew]

    Pthread线程使用模型之二工作组(Work crew) 场景 1.一些耗时的任务,比如分析多个类型的数据, 是独立的任务, 并不像 pipeline那样有序的依赖关系, 这时候pipeline就显 ...

  4. [并发并行]_[线程模型]_[Pthread线程使用模型之一管道Pipeline]

    场景 1.经常在Windows, MacOSX 开发C多线程程序的时候, 经常需要和线程打交道, 如果开发人员的数量不多时, 同时掌握Win32和pthread线程 并不是容易的事情, 而且使用Win ...

  5. 分享一个关于pthread线程栈在mm_struct里面的分布问题

    大家好,本人被下面这个问题困扰了一段时间,最近似乎找到了答案. 这里和大家分享一下,可能对有相同困惑的同学有点帮助,同时也请各位帮忙看看错漏的地方. 1================问题: 在使用p ...

  6. 【C/C++多线程编程之五】pthread线程深入理解

    多线程编程之pthread线程深入理解       Pthread是 POSIX threads 的简称,是POSIX的线程标准.           前几篇博客已经能给你初步的多线程概念.在进一步学 ...

  7. 【C/C++多线程编程之十】pthread线程私有数据

    多线程编程之线程私有数据      Pthread是 POSIX threads 的简称.是POSIX的线程标准.         线程同步从相互排斥量[C/C++多线程编程之六]pthread相互排 ...

  8. [转]c++多线程编程之pthread线程深入理解

    多线程编程之pthread线程深入理解         Pthread是 POSIX threads 的简称,是POSIX的线程标准.           前几篇博客已经能给你初步的多线程概念.在进一 ...

  9. pthread 线程立即取消的两种方法

    1.相关函数介绍 a. int pthread_cancel(pthread_t thread) 1发送终止信号给thread线程,如果成功则返回0,否则为非0值.发送成功并不意味着thread会终止 ...

  10. C++代码利用pthread线程池与curl批量下载地图瓦片数据

    项目需求编写的程序,稳定性有待进一步测试. 适用场景:在网络地图上,比如天地图与谷歌地图,用户用鼠标在地图上拉一个矩形框,希望下载该矩形框内某一层级的瓦片数据,并将所有瓦片拼接成一个完整的,包含地理坐 ...

随机推荐

  1. Linux配置IP和防火墙

    前言: 刚刚学完了怎么配置Linux IP和防火墙 前来总结. 准备: 需安装的: setup 正文: 安装基础包 yum groupinstall "Base" setup 选择 ...

  2. leetcode529

    public class Solution { //DFS public char[,] UpdateBoard(char[,] board, int[] click) { ), n = board. ...

  3. 「小程序JAVA实战」小程序视图之细说列表渲染(14)

    转自:https://idig8.com/2018/08/09/xiaochengxu-chuji-14/ 列表的渲染,不管是任何语言都有列表这个概念.源码:https://github.com/li ...

  4. mybatis与springdata的一些简单比较与思考

    主题 最近在用mybatis做项目,有一些感触想记录下,主要是mybatis(以及它的一些插件)相比较于Spring data(或者jpa,hibernate等)的优势地方. 感触 我觉得mybati ...

  5. Failed to start component [StandardEngine[Catalina].

    出现以下的错误的原因: 检查 web.xml文件,应该是<filter>和<filter-mapping>或者<servlet>和<servlet-mappi ...

  6. think in avalon

    1.不要设计,也不要通过DOM操作去改变你的页面 你用jQuery去设计一个页面,并让它动起来.这是因为jQuery就是让一切简单的事情变复杂的罪魁祸首. 但是用avalon,你必须从零开始去构思你的 ...

  7. PHP - 脚本退出(包括异常退出),执行指定代码

    之前做聊天室的时候有那么个需求就是当用户异常断线的时候就应该清除她的在线状态.因为当时对于flush不够了解,尝试了各种办法,好像都没办法在我们开发机上面执行相应的代码.后来知道是flush的原因.我 ...

  8. Elasticsearch-PHP 搜索操作

    搜索操作 好吧,这不叫elasticsearch的不劳而获!让我们来谈谈PHP客户端中的搜索操作. 客户端允许你通过REST API访问所有的查询和公开的参数,尽可能的遵循命名规则.让我们来看一些例子 ...

  9. 网页静态化解决方案:Freemarker生成简单html页面

    FreeMarker 是一个用 Java 语言编写的模板引擎,它基于模板来生成文本输出.FreeMarker与 Web 容器无关,即在 Web 运行时,它并不知道 Servlet 或 HTTP.它不仅 ...

  10. Android中的网络编程

    谷歌在Android6.0之后就废弃了使用HttpClinet进行网络连接.所以,这里需要重点学习的是通过HttpUrlConnect进行网络连接. String path="这里是你想要的 ...