Linux多线程学习(一):线程的创建和终止
一、Linux下线程的定义
线程是包含在进程内部的顺序执行流,是进程中的实际运作单位,也是操作系统能够进行调度的最小单位。一个进程中可以并行多个线程,每条线程并行执行不同的任务。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
二、线程与进程的关系
1、一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个主线程;
2、进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源,同一进程的所有线程共享改进程的所有资源。
3、Linux下不管是多线程编程还是多进程编程,最终都是用do——fork()实现的多进程编程,只是在进程创建时的参数不同,从而导致有不同的共享环境。
4、进程相对于线程最大的区别是有内核保证的隔离:数据和错误隔离。即一个进程崩溃不会引起其他进程的崩溃,而同一进程下的线程则不然。
三、多线程的创建与终止
1、线程的创建
1.1 线程创建函数:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
(1)pthread:线程的句柄,用来指向新创建的线程,是一个无符号长整型类型;
(2)attr:用来表示一个封装了线程各种属性的属性对象,如果attr设置为NULL,则线程以默认的属性创建。
(3)start_routine:是一个返回值为(void*)的线程入口函数;
(4)arg:arg为线程入口函数的参数,类型为(void*);
返回值:线程创建成功返回一个0,否则返回一个非0值,非0值包括:
(1)EAGAIN ,系统没有创建线程所需的资源;
(2)EINVAL ,attr 参数无效;
(3)EPERM 调用程序没有适当的权限来设定调度策略或 attr 指定的参数。
1.2 pthread_attr_t
attr是一个结构体,定义如下:
typedef struct
{
int detachstate; 线程的分离状态
int schedpolicy; 线程调度策略
struct sched_param schedparam; 线程的调度参数
int inheritsched; 线程的继承性
int scope; 线程的作用域
size_t guardsize; 线程栈末尾的警戒缓冲区大小
int stackaddr_set; 堆栈的地址集
void * stackaddr; 线程栈的位置
size_t stacksize; 线程栈的大小
}pthread_attr_t;
结构体成员的具体含义和取值可参考这个帖子,写的很详细:
https://blog.csdn.net/hudashi/article/details/7709413
2、线程的终止
函数:void pthread_exit(void *retval);
retval 是一个 void 类型的指针,可以将线程的返回值当作 pthread_exit()的参数传入,这
个值可以被 pthread_join()当作退出状态接收。如果没有返回值,则赋值为NULL。
注:pthread_join(pthread_t thread ,void **rval_ptr)中,thread 为等待线程的id,是用户定义的指针,用来存储被等待线程的返回值。
进程终止时,进程下面的所有线程都会终止,在遇到下面某一种情况时,都可以使进程终止:
(1)进程的终止可以通过直接调用 exit();
(2)执行 main()中的 return;
(3)通过进程的某个其它线程调用 exit()。
调用 exit()函数会使整个进程终止,而调用 pthread_exit()只会使得调用线程终止。需要注意的是return会隐式的调用pthread_exit函数。
测试代码:新建一个线程,并在新建的线程中打印5次字符串后,退出线程。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread>
void *pthread_test(void * pra)
{
int parm;
int i = 0;
parm = (int)pra;
while( (i++)<5 )
{
printf("I am running,receive data is %d\r\n",parm)
sleep(1);
}
pthread_exit(NULL);
}
int main(void)
{
pthread_t thread;
int res;
int pra = 1;
res = pthread_create(&thread,NULL,pthread_test,(void *)pra);
if(res)
{
printf("thread create fail\r\n");
exit(-1);
}
pthread_exit(NULL);
return 0;
}
运行结果:
注意事项:
(1)主函数的最后必须调用pthread_exit()函数,否则遇到return,进程终止,子线程也将终止。
(2)编译代码时,需要在makefile中加入 LDFLAGS += -pthread;
(3)线程创建成功后,立即执行;