前言
什么是线程?我们首先要知道的一件事情是一个进程里面可以包括多个线程,不能反过来,我们之前了解到的不同进程可以做不一样的事情,我们举一个简单易懂的例子:我们的电脑上面有很多的应用程序,微信、QQ,酷狗音乐等等,我们运行一个应用程序就有一个进程,那什么是线程呢?比如其中一个,我们打开了酷狗音乐,打开音乐听着,这时候你觉得歌好听你就去看评论,这时候你想一下:播放音乐,看评论。是两件事情,但是都可以同时进行,那这里我们说酷狗音乐是一个进程,听音乐和看评论是它下面的两个线程。
你要记住单进程里面执行多个任务,这就是线程。
一、原理图
二、线程
1.线程标识
和进程一样,线程也有一个唯一标识;进程标识是pit_t数据类型来表示,线程是用pthread_t数据类型来表示。获取自己的线程标识我们用函数pthread_self();
2.线程创建
在外面没有创建新的线程的时候,运行的时候他和普通进程没没有什么区别。我们创建出来的线程是共享全部变量在子线程改变全局变量那么主线程也会被改变,这一点一会我们可以验证一下。
pthread_create
创建新线程可以使用函数pthread_create()来创建,它的主要参数如下:
参数1:pthread_t *tid
传出参数,表示新创建的子线程ID。线程的标识类型,pthread_t在头文件/usr/include/bits/pthreadtypes.h中定义:typedef unsigned long int pthread_t;
参数2:const pthread_attr_t *attr
线程属性,传入NULL表示使用默认属性;当此函数设置为空指针时,将生成默认的线程属性;
参数3:void *(*start_rountn)(void *)
子线程的回调函数,创建成功,pthread_create函数返回时,该函数会被自动调用;这个参数是运行函数的起始地址;
参数4:void *arg
给回调函数传的参数,如果函数不需要传参传NULL.
当线程创建成功时,函数返回0,若不为0则说明线程创建失败;常见的错误返回码为EAIN和EINVAL。前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。
pthread_join
函数pyhread_join 用来等待一个线程的结束。函数原型为:
extern int pthread_join _p(pthread_t _th,void**_thread_return);
第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来等待线程的返回值。这个函数是一个线程阻塞的函数。调用它的函数将一直等待到被等待线程结束为止,当函数返回时,被等待线程的资源被回收;
pthread_exit
线程除了正常执行结束外,还可以通过函数pthread_exit来结束它,pthread_exit的函数原型为:
void pthread_exit(void* __return_value) __noreturn;
唯一的参数是函数返回代码;只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给thread_return。最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH;
代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
int a=10;
void * fun1(void * arg)
{
pthread_detach(pthread_self());
a=100;
printf("子线程 进程号:%d, 线程号:%lu\n",getpid(),pthread_self());
}
int main ()
{
pthread_t tid;
printf("主线程 进程号:%d, 线程号:%lu\n",getpid(),pthread_self());
//创建线程
printf("a=%d\n",a);
int ret =pthread_create(&tid,NULL,fun1,NULL);
if(ret==0)
{
printf("线程创建成功!\n");
}
sleep(2);
printf("a=%d\n",a);
return 0;
}
另外一个值得我们注意的是我们的全局变量a我们在定义的时候值是10,然后我们在线程里面把值改为了100,最后打印出来的结果验证了我们前面说的线程是共享全局变量的。
3.修改线程属性
属性结构为pthread_attr_t,在头文件/usr/include/pthread.h中定义。属性值不能直接设置,须使用相关函数进行操作,初始化函数为 pthread_attr_init,这个函数必须在pthread_create函数之前调用。属性对象主要包括是否绑定、是否分离、堆栈地址、堆栈大小、优先级。默认的属性为非绑定、非分离、缺省1M的堆栈、与父进程同样级别的优先级。
4.线程与进程
4.线程分离
int pthread_detach(pthread_t thread); 设置线程分离,使用detach分离线程,分离后的线程会自动回收。
参数: thread 是要分离的线程ID。
成功返回0,失败返回errno。
5.线程退出
pthread_exit 退出
void pthread_exit(void *retval); 退出当前线程。
retval:退出值。 无退出值时,NULL
exit(); 退出当前进程。
return: 返回到调用者那里去。pthread_exit(): 退出当前线程。
总结
关于线程的使用不仅于此,在线程编程中还有很多重要的知识,后期再更新对线程更深入地探讨。