Linux pthread 线程 浅解
2016-04-01 13:55
513 查看
线程
问题
使用fork创建进程以执行新的任务,该方式的代价很高。
解决办法:使用线程
什么是线程
线程,是进程内部的一个控制序列。
即使不使用线程,进程内部也有一个执行线程。
类比:创建一个进程,类似于“克隆”一个家庭。
该“家庭”与原来的家庭完全相同
但是新“家庭”和原来的家庭完全独立。
注意:单核处理器上,同一个时刻只能运行一个线程。
但是对于用户而言,感觉如同同时执行了多个线程一样
(各线程在单核CPU上切换,在一段时间内,同时执行了多个线程)
线程的优点、缺点
优点: 创建线程比创建进程,开销要小。
缺点: 1)多线程编程,需特别小心,很容易发生错误。
2)多线程调试很困难。
3)把一个任务划分为两部分,
用两个线程在单处理器上运行时,不一定更快。
除非能确定这两个部分能同时执行、且运行在多处理器上。
线程的应用场合
1) 需要让用户感觉在同时做多件事情时,
比如,处理文档的进程,一个线程处理用户编辑,一个线程同时统计用户的字数。
2) 当一个应用程序,需要同时处理输入、计算、输出时,
可开3个线程,分别处理输入、计算、输出。
让用户感觉不到等待。
线程的使用
1)线程的创建
pthread_create
原型:int pthread_create (
pthread_t *thread,
pthread_attr_t *attr,
void (*start_routine)(void),
void *arg);
参数:thread, 指向新线程的标识符。
通过该指针返回所创建线程的标识符。
attr, 用来设置新线程的属性。
一般取默认属性,即该参数取NULL
start_routine, 该线程的处理函数
该函数的返回类型和参数类型都是void*
arg, 线程处理函数start_routine的参数
功能:创建一个新线程,
同时指定该线程的属性、执行函数、执行函数的参数
通过参数1返回该线程的标识符。
返回值:成功,返回0
失败,返回错误代码
注意:大部分pthread_开头的函数成功时返回0,失败时返回错误码(而不是-1)
注意:使用fork创建进程后,进程 马上就启动,但是是和父进程同时执行fork之后后的代码。
使用pthread_create创建线程后,新线程马上就启动,即执行对应的线程处理函数。
2)线程的终止
pthread_exit
原型:void pthread_exit (void *retval)
功能:在线程函数内部调用该函数。
终止该线程,并通过参数retval返回一个指针。
该指针不能指向该线程的局部变量。
3)等待指定线程结[
pthread_join
功能:类似与进程中的waitpid
等待指定的线程结束,并使参数指向该线程函数的返回值(用pthread_exit返回的值)
原型:int pthread_join (pthread_t th,
void ** thread_return);
参数:th, 指定等待的线程
thread_return, 指向该线程函数的返回值
线程函数的返回值类型为void*,故该参数的类型为void**
4)使用线程程序的编译
(1) 编译时,定义宏_REENTRANT
即: gcc -D_REENTRANT (#define REENTRANT)
4)实例
main1.c
实例
创建一个线程,并传递一个字符串
在新线程中,把所传递的字符串打印出来,
并把字符串转换为大写,再返回给主线程
新线程结束后,在主线程中,把所返回的结果打印输出。
main1.c
问题
使用fork创建进程以执行新的任务,该方式的代价很高。
解决办法:使用线程
什么是线程
线程,是进程内部的一个控制序列。
即使不使用线程,进程内部也有一个执行线程。
类比:创建一个进程,类似于“克隆”一个家庭。
该“家庭”与原来的家庭完全相同
但是新“家庭”和原来的家庭完全独立。
进程包含一个或多个线程。 类似与一个家庭,包含一个或多个家庭成员。 家庭内的各成员同时做各自的事情(父亲工作、母亲持家、小孩上学) 而对于家庭外部的人来说,这个家庭同时在做多件事情。 家庭内的每个成员,就是一个线程。 各个家庭成员有自己的个人资源(线程有自己的局部变量) 但是所有家庭成员都能共享这个家庭的资源:房子、汽车、家庭的公共资金。 (同一个进程内的各个线程,能够共享整个进程的全局变量,除了线程的局部变量外,其他资源都共享)
注意:单核处理器上,同一个时刻只能运行一个线程。
但是对于用户而言,感觉如同同时执行了多个线程一样
(各线程在单核CPU上切换,在一段时间内,同时执行了多个线程)
线程的优点、缺点
优点: 创建线程比创建进程,开销要小。
缺点: 1)多线程编程,需特别小心,很容易发生错误。
2)多线程调试很困难。
3)把一个任务划分为两部分,
用两个线程在单处理器上运行时,不一定更快。
除非能确定这两个部分能同时执行、且运行在多处理器上。
线程的应用场合
1) 需要让用户感觉在同时做多件事情时,
比如,处理文档的进程,一个线程处理用户编辑,一个线程同时统计用户的字数。
2) 当一个应用程序,需要同时处理输入、计算、输出时,
可开3个线程,分别处理输入、计算、输出。
让用户感觉不到等待。
线程的使用
1)线程的创建
pthread_create
原型:int pthread_create (
pthread_t *thread,
pthread_attr_t *attr,
void (*start_routine)(void),
void *arg);
参数:thread, 指向新线程的标识符。
通过该指针返回所创建线程的标识符。
attr, 用来设置新线程的属性。
一般取默认属性,即该参数取NULL
start_routine, 该线程的处理函数
该函数的返回类型和参数类型都是void*
arg, 线程处理函数start_routine的参数
功能:创建一个新线程,
同时指定该线程的属性、执行函数、执行函数的参数
通过参数1返回该线程的标识符。
返回值:成功,返回0
失败,返回错误代码
注意:大部分pthread_开头的函数成功时返回0,失败时返回错误码(而不是-1)
注意:使用fork创建进程后,进程 马上就启动,但是是和父进程同时执行fork之后后的代码。
使用pthread_create创建线程后,新线程马上就启动,即执行对应的线程处理函数。
2)线程的终止
pthread_exit
原型:void pthread_exit (void *retval)
功能:在线程函数内部调用该函数。
终止该线程,并通过参数retval返回一个指针。
该指针不能指向该线程的局部变量。
3)等待指定线程结[
pthread_join
功能:类似与进程中的waitpid
等待指定的线程结束,并使参数指向该线程函数的返回值(用pthread_exit返回的值)
原型:int pthread_join (pthread_t th,
void ** thread_return);
参数:th, 指定等待的线程
thread_return, 指向该线程函数的返回值
线程函数的返回值类型为void*,故该参数的类型为void**
4)使用线程程序的编译
(1) 编译时,定义宏_REENTRANT
即: gcc -D_REENTRANT (#define REENTRANT)
功能:告诉编译器,编译时需要可重入功能。 即使得,在编译时,编译部分函数的可重入版本。 (2) 编译时,指定线程库 即: gcc -lpthread 功能:使用系统默认的NPTL线程库, 即在默认路径中寻找库文件libpthread.so 默认路径为/usr/lib和/usr/local/lib 当系统默认使用的不是NPTL线程库时(系统较老,2003年以前) 指定:gcc -L/usr/lib/nptl -lpthread 补充: -L 指定库文件所在的目录 -l 指定库文件的名称(-lpthread ,指库文件名为libpthread.so) 总结:一般使用如下形式即可 gcc -D_REENTRANT -lpthread mythread.c -o mythread
4)实例
main1.c
实例
创建一个线程,并传递一个字符串
在新线程中,把所传递的字符串打印出来,
并把字符串转换为大写,再返回给主线程
新线程结束后,在主线程中,把所返回的结果打印输出。
#ifdef FUNC_A void test_func(void) { printf("world"); } #else void test_func(void) { printf("hello"); } #endif
main1.c
#include <pthread.h> #include <stdio.h> #include <stdlib.h> int my_global; void* my_thread_handle(void *arg) { int val; val = *((int*)arg); printf("new thread begin, arg=%d\n", val); my_global += val; sleep(3); pthread_exit(&my_global); // ≤ª‘Ÿ÷¥–– printf("new thread end\n"); } int main(void) { pthread_t mythread; int arg; int ret; void *thread_return; arg = 100; my_global = 1000; printf("my_global=%d\n", my_global); printf("ready create thread...\n"); ret = pthread_create(&mythread, 0, my_thread_handle, &arg); if (ret != 0) { printf("create thread failed!\n"); exit(1); } printf("wait thread finished...\n"); ret = pthread_join(mythread, &thread_return); if (ret != 0) { printf("pthread_join failed!\n"); exit(1); } printf("wait thread end, return value is %d\n", *((int*)thread_return)); printf("my_global=%d\n", my_global); printf("create thread finished!\n"); }
相关文章推荐
- Ubuntu下安装LXC手记之centos
- 嵌入式linux:阻塞与非阻塞驱动
- Linux下利用ioctl函数获取网卡信息
- diffuse linux 文件比对工具
- 在CentOS7上安装MySQL
- Linux vmstat具体解释(系统IO)
- GPRS模块在Linux平台上ppp拨号上网总结与心得
- Linux 下让进程在后台可靠运行的几种方法
- Linux系统中 安装Vmware Toolst工具
- Linux 2.6内核中新的锁机制RCU
- linux上xls文件转db文件的方法
- linux 动态链接器相关
- Linux日志清除
- 在Centos7上安装python3.5,以及与旧版本python2.7.5的共存问题
- Linux _守护进程 浅解
- Linux内核中的GPIO系统之(3):pin controller driver代码分析
- Linux中常用命令详解
- Linux _孤儿进程和僵尸进程 浅见
- ZedBoard Linux开发 --- GPIO驱动详解
- Linux vmstat命令实战详解