一.为什么要使用线程
在没有线程的情况下,进程是程序执行流的最小单位,程序的执行可以被分割成很多进程来实现,但对于有些细微的过程,如果组织一个进程来执行,会比较浪费资源,因为,我
们都知道每个进程的创建都是要开辟整块的进程空间,代码段,数据段,堆,栈等,而线程就是一个很好的选择,线程有如下有点:
线程间的共享数据比进程间共享简单的多
线程的创建更加快速
线程使用占用更少的资源
但线程也有自己的缺点:
使用线程编程,我们必须确认自己的线程安全(多线程常常因为不当的共享数据访问而出问题)
一个线程中的bug很可能使所有线程都挂掉
多个线程需要竞争其所在进程地址空间
二.线程概述
一个进程可以有多个线程,它们虽然分开执行,但是它们共享全局变量,包括:初始数据,未初始数据,堆,但每个线程都有自己单独的栈(调用函数必须用到)
线程的内存分配图
三.linux线程API
1.线程数据类型
Data type | Description |
pthread_t | Thread identifier |
pthread_mutex_t | Mutex |
pthread_mutexattr_t | Mutex attributes object |
pthread_cond_t | Condition variable |
pthread_condattr_t | Condition variable attributes object |
pthread_key_t | Key for thread-specific data |
pthread_once_t | One-time initialization control context |
pthread_attr_t | Thread attributes object |
2.线程和errno
在linux中,errno被设定为一个全局的整型,很明显对于线程这种方法并不适用,因为多个线程会竞争使用errno,而结果就是errno中存储的错误值未必能够对应到出现错误的线程。所以在linux将errno设定为一系列可以根据返回值区分线程的宏函数。
3.线程函数的返回值
和普通函数不同,线程函数返回0代表成功,负数代表失败
4.线程的创建
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start)(void *), void *arg);
thread指向一个pthread_t类型的buf,其中存放着线程的标识符,start指向线程的调用函数,arg是传给调用函数的参数,attr指向一个设定线程的属性结构体
5.线程的结束
线程的结束方式:
线程函数返回
线程调用pthread_eixt()
线程通过pthread_cancel()被取消
任何线程调用exit(),或者主线程return,都会让所有线程结束
include <pthread.h>
void pthread_exit(void *retval);
6.线程ID
include <pthread.h>
pthread_t pthread_self(void);
每个线程通过其ID被唯一标识,这个ID可以通过pthread_self()函数活得
include <pthread.h>
int pthread_equal(pthread_t t1, pthread_t t2);
pthread_equal函数可以被用来检测两个两个线程ID是否相同
7.等待线程结束
include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
pthread_join函数可以用来等待指定ID线程结束,如果该线程已经结束,则该函数立马返回,如果retval为非空指针,那么它将复制一份线程函数的返回值
8.隔离一个线程
默认情况下,每个线程都是可以被等待结束的,有些情况下我们不需要关注一个线程的返回状态,只想在它结束之后立马收回资源,这个时候我们可以隔离(detach)该线程
#include <pthread.h>
int pthread_detach(pthread_t thread);
一个线程被隔离之后,便无法被等待结束,而且一旦被隔离,便无法被恢复
-------------------------------------------------------------------------------------------------------------------------
线程测试代码,这段代码根据用户输入参数个数为创建线程个数,对应为线程名
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
void * threadFunc(void * arg)
{
printf("This is thread %s, it's ID is %lu!\n",(char *)arg,pthread_self());
}
int main(int argc, char ** argv)
{
pthread_t * pt;
int i, s;
if(1 == argc )
perror("Wrong arguments!");
else
{
pt = calloc(argc -1, sizeof(pthread_t));
for(i=1;i<argc;i++)
{
s = pthread_create(&pt[i-1], NULL, threadFunc, argv[i]);
if(0!=s)
perror("thread create failed!");
printf("thread No%d has created!\n",i);
}
for(i=1;i<argc;i++)
{
s = pthread_join(pt[i-1], NULL);
if(0!=s)
perror("thread join failed!");
printf("thread No%d has terminated!\n",i);
}
}
return 0;
}
运行结果: