线程概述
线程是进程内独立的一条运行路线,处理器调度的最小单元,也可以称为轻量级进程。线程可以对进程的内存空间和资源进行访问,并与同一进程中的其他线程共享。因此,线程的上下文切换的开销比创建进程小很多。
线程vs进程
线程机制的分类和特性
线程按照其调度者可以分为用户级线程和核心级线程两种。
(1)用户级线程
由用户应用程序创建的线程,并且由用户应用程序负责所有这些用户级线程的调度执行和管理工作。
优点:运行时不需要内核支持,线程切换速度较快;
缺点:一个线程阻塞会导致进程中的其他线程也阻塞,无法发挥多处理器的优势;
(2)轻量级进程
内核支持的用户线程,是内核线程的一种抽象对象,用户线程可通过复用来关联到内核分配给用户的轻量级进程。
(3)内核线程
所有线程的创建、调度和管理全部由操作系统内核负责
允许不同进程中的线程按照统一相对优先调度方法进行调度,这样就可以发挥多处理器的优势。
现代操作系统一般都采用用户级线程与核心级线程并存的方法。这样既可以满足多处理机系统的需要,也可以最大限度地减少调度开销。但线程机制增加了程序的实现复杂度。
pthread线程库
Pthread是一套用户级线程库,但在linux上实现时,却使用了内核级线程来完成,这样提高的线程的并发性.Pthread是由POSIX提供的一套通用的线程库,具有很好的移植性.
创建线程
创建线程的主要任务就是确定线程入口函数,这里通常使用的函数是pthread_create( )。如果该函数执行成功,线程就自动开始运行了。
正如进程之间可以用wait()系统调用来同步终止并释放资源一样,线程之间也有类似机制,那就是pthread_join()函数。
pthread_join()可以用于将当前线程挂起来等待另一个线程的结束,通常用于线程间同步。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源就被收回。
pthread_join使一个线程等待另一个线程结束。
代码中如果没有pthread_join主线程会很快结束从而使整个进程结束,从而使创建的线程没有机会开始执行就结束了。加入pthread_join后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行。
所有线程都有一个线程号,也就是Thread ID,其类型为pthread_t。通过调用pthread_self()函数可以获得自身的线程号。
线程入口函数运行完之后,该线程也就退出了,这也是线程退出一种方法(线程自然“死亡”)。
另一种退出线程的方法是使用函数pthread_exit(),这是线程的主动行为,注意,绝对不可以使用exit()退出!!!。
前面已提到线程调用pthread_exit()函数主动终止自身线程。
但是在很多线程应用中,经常会遇到在别的线程中要终止另一个线程的执行的问题。此时调用pthread_cancel( )函数实现这种功能
代码实战
#include
#include
#include //调用linux线程函数必须包含此头文件
#define THREAD_NUMBER 3
#define REPEAT_NUMBER 5
#define DELAY_TIME_LEVELS 10.0
void * thrd_func(void *arg)//子线程入口函数
{
int thrd_num = (int)arg; //主线程对每个线程自定义了一个编号,放在参数arg中
int delay_time = 0;
int count = 0;
printf("Thread %d is starting\n", thrd_num);
for (count = 0; count < REPEAT_NUMBER; count++)
{
//rand()为随机数产生函数,其随机数的最大值为RAND_MAX(系统定义),
//(int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX))将会得到一个0——9之间的随机数,注意//强制类型转换int不能省!!
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1;
sleep(delay_time);//睡眠
printf("\tThread %d: job %d delay = %d\n", thrd_num, count, delay_time);
}
printf("This is son thread,Thread %d finished\n", thrd_num);
pthread_exit(NULL);//线程退出,这里也可以不要此语句,让线程“自然死亡”!
}
int main(void)//主线程入口
{
pthread_t thread[THREAD_NUMBER];//声明此数组用来保存子线程号
int num = 0, res;
void * thrd_ret;
srand(time(NULL));//用当前时间作为一个随机数种子,否则随机数序列每次有一样!
for (num = 0; num < THREAD_NUMBER; num++)
{
//num的值将传递给线程入口函数
res = pthread_create(&thread[num], NULL, thrd_func, (void*)num);//创建子线程
if (res != 0)
{
printf("Create thread %d failed\n", num);
exit(res);
}
printf("Created thread %d success!\n", num);
}
printf("Created threads success\n Waiting for threads to finish...\n");
for (num = 0; num < THREAD_NUMBER; num++)
{
printf("wait thread %d to finish!\n", num);
//按创建顺序逐个等待子线程结束
res = pthread_join(thread[num], &thrd_ret);
if (!res)
{
printf("This is father thread,Thread %d finished\n", num);
}
else
{
printf("Thread %d join failed\n", num);
}
}
return 0;
}