linux多线程编程基础函数介绍
来源:互联网 发布:js控制标签显示隐藏 编辑:程序博客网 时间:2024/06/06 07:10
linux多线程编程基础函数介绍
Linux操作系统提供了pthread线程库,它是符合POSIX标准的函数库。线程控制方面的函数定义在pthread.h文件中,信号量控制方面的函数定义在semaphore.h文件中。
- 线程控制方面的函数有:pthread_attr_init、pthread_create、pthread_join、pthread_exit
- 互斥锁机制函数:pthread_mutex_init、 pthread_mutex_lock、 pthread_mutex_unlock、 pthread_mutex_destroy
- 条件变量函数:pthread_cond_init、int pthread_cond_signal、int pthread_cond_wait、int pthread_cond_destroy、pthread_cond_broadcast
- 信号量线程控制函数:sem_init、sem_wait、sem_post、sem_getvalue、sem_destory
本文中包含以上大部分函数的基本用法,用于后期一道大程的设计和编写。其中信号量这一块不单独属于多线程编程部分,在此暂时先不讲。
参考书籍:unix高级编程第11章。
线程的标识
线程的ID: 用pthread_t的数据类型表示
ID比较:int pthread_equal(pthread_t tid1, pthread_t tid2)
ID获取:pthread_t pthread_self(void)
线程的创建、等待、结束
线程的创建:
int pthread_create(pthread_t restricttidp, const pthread_attr_t *restrict attr,void (start_rtn)(void), void *restrict arg);
其中,tidp指向的内存单元存储新创建线程的线程ID,attr先设置为null, 新创建的进程从start_rtn的函数地址开始运行,arg为需要传递的参数。
线程的等待:int pthread_join(pthread_t thread, void **rval_ptr);
线程的结束:int pthread_exit(void *rval_ptr);
线程的取消:int pthread_cancel(pthread_t tid);
一般线程的结束可以通过三种途径:线程执行完毕,线程被同一进程中的其他线程取消(pthread_cancel),自己调用pthread_exit。注意,pthread_cancel不等待线程终止,仅向线程提出取消请求。
再来解释一下rval_ptr参数。当线程1采用err = pthread_join(thread2, &res)等待线程2的时候,线程2调用pthread_exit((void *)1),此时res值即为exit返回的参数1。同时还可以通过这个指针来传递复杂的结构体,但必须注意在传递回线程1后内存仍必须是有效的。
下面的程序用多线程实现斐波那契数列的计算。其中子线程用于计算斐波那契数列中每一个项的值,主线程负责输出。
#include <stdio.h>#include <string.h>#include <pthread.h>#include <unistd.h>pthread_t thread_id;int num;void *thread_calc(int arr[]){ for (int i=2; i<=num; i++) arr[i] = arr[i-1] + arr[i-2]; return NULL; pthread_exit(NULL);}int main(){ int* arr; scanf("%d", &num); arr = (int*)malloc(sizeof(int) *(num+1)); arr[0] = 0; arr[1] = 1; int res = pthread_create(&thread_id, NULL, thread_calc, arr); if (res == -1) printf("Thread create failed!"); printf("Waiting for the thread to compute!\n"); pthread_join(thread_id, NULL); for (int i=0; i<=num; i++) printf("array[%d] = %d\n",i,arr[i]);}
线程同步
线程的同步主要通过互斥变量来完成。简单的来说就是跟数据库里一样,对这个程序正在进行读写的资源加锁,其他任意想要访问这个资源的线程都会被阻塞。互斥变量用pthread_mutex_t数据类型来表示,初始化方式有两种:
- 把其设置为常量PTHREAD_MUTE_INITIALIZER(只适用于静态分配的互斥量)
- 调用int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
同时如果动态分配互斥量(malloc),需要用pthread_mutex_destory(pthread_mutex_t *mutex)来释放内存。
对互斥量加锁解锁的函数为以下三个:
- int pthread_mutex_lock(pthread_mutex_t *mutex);
- int pthread_mutex_unlock(pthread_mutex_t *mutex);
- int pthread_mutex_trylock(pthread_mutex_t *mutex);
以下代码为一个很简答的实例,两个子线程分别对global_count进行加减,同时调用sleep使得每两次调用sub才会调用一次add。
#include <stdio.h>#include <pthread.h>#include <unistd.h> //unistd.h 是 C 和 C++ 程序设计语言中提供对 POSIX 操作系统 API 的访问功能的头文件的名称。#include <stdlib.h>void* thread_add();void* thread_sub();pthread_t th_add, th_sub; pthread_mutex_t lock;int global_count = 0;int main(){ int res; res = pthread_mutex_init(&lock, NULL); if (res == -1) { printf("Create mutex failed!\n"); exit(1); } res = pthread_create(&th_add, NULL, thread_add, NULL); if (res == -1) { printf("Create thread failed!\n"); exit(1); } res = pthread_create(&th_sub, NULL, thread_sub, NULL); if (res == -1) { printf("Create thread failed!\n"); exit(1); } pthread_join(th_add, NULL); pthread_join(th_sub, NULL);}void* thread_add(){ while (global_count < 20) { sleep(2); pthread_mutex_lock(&lock); printf("Before add: %d\n", global_count); global_count += 5; printf("After add: %d\n", global_count); pthread_mutex_unlock(&lock); } pthread_exit(NULL);}void* thread_sub(){ while (global_count > -20) { sleep(1); pthread_mutex_lock(&lock); printf("Before sub: %d\n", global_count); global_count -= 5; printf("After sub: %d\n", global_count); pthread_mutex_unlock(&lock); } pthread_exit(NULL);}
如果一段程序有种两个互斥量(锁)的时候,就很容易出现死锁的情况。死锁为线程1锁住资源a,同时正在请求资源b,同时线程2锁住资源b,同时正在请求资源a。该情况复杂的多,具体实例可以详见unix高级编程第11章6.2。
条件变量
条件变量的数据类型:
pthread_cond__t
条件变量的创建:
intpthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr,);
条件变量的反初始化:
intpthread_cond_destroy(pthread_cond_t *cond);
主要的三个函数:
int pthread_cond_wait(pthread_cond_t *restrict bond, pthread_mutex_t *restrict mutex);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
其中,在调用wait的时候,需要将互斥量一起传给函数。函数在收到互斥量并开始等待后,会先将互斥量解锁,方便其他线程先运行。signal和broadcast用于通知wait,其中signal通知一个及以上,broadcast通知所有的等待在消息队列中的条件。
- linux多线程编程基础函数介绍
- Linux多线程编程之基础函数
- linux多线程编程介绍
- Linux多线程编程基础
- linux 多线程编程基础
- linux基础编程 多线程
- linux基础编程 多线程
- Linux 多线程编程基础
- Linux多线程编程函数
- linux C++多线程编程介绍
- 并发基础 -- Linux多线程编程
- linux多线程编程基础1
- linux多线程编程基础入门
- Linux进程编程基础介绍
- Linux进程编程基础介绍
- 多线程编程——prctl()函数介绍
- [Linux C]Linux多线程编程基础
- POSIX---linux多线程编程基础入门。
- 2017-2018 ACM-ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Prefer
- 斯坦福机器学习笔记 第2周 五、Octave教程(一)
- Python视觉处理(四)HSV处理
- sublime VI编辑器 十分钟熟练掌握各种命令
- zlib库 在windows下的编译与使用
- linux多线程编程基础函数介绍
- 笔记:pringMVC执行流程解析
- Java基础总结
- centos 7搭建vsftp安装,配置,卸载,常见错误
- Windows编程基础--第6节 VC++6.0控件说明
- JavaScript加密库Crypto-JS的使用
- Prometheus 到底 NB 在哪里?- 每天5分钟玩转 Docker 容器技术(84)
- 【天籁纯音】-细腻 醇厚 深情《似人声 如马鸣·马头琴典藏PartⅠ》(MP3∥320K)‖〔WAV∥(DTS-ES6_1)VS(DTS-DS5_1)〕
- 计蒜客之字符乘积