Linux线程实现
一、什么是线程
在一个程序里的一个执行路线就叫做线程。
二、线程优点
·创建一个新线程的代价要比创建一个新进程小得多。
·与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多。
·线程占用的资源要比进程少很多。
·能充分利用多处理器的可并行数量。
·在等待慢速IO操作结束的同时,程序可执行其他的计算任务。
·计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现。
·IO密集型应用,为了提高性能,将IO操作重叠,线程可以同时等待不同的IO操作
三、线程缺点
·性能损失: 一个很少被外部事件阻塞的计算密集型线程往往无法与其他线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变。
·健壮性降低: 编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话说,线程之间是缺乏保护的。
·缺乏访问控制: 进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。
·编程难度提高: 编写与调试一个多线程程序比单线程程序困难得多。
四、Linux线程控制
1、POSIX线程库
是POSIX的线程标准,定义了创建和操纵线程的一套API。注意:pthread不是Linux下的默认库,所以在编译的时候要附-lpthread
2、线程创建
函数原型
/* Create a new thread, starting with execution of START-ROUTINE
getting passed ARG. Creation attributed come from ATTR. The new
handle is stored in *NEWTHREAD. */
extern int pthread_create (pthread_t *__restrict __newthread, const pthread_attr_t *__restrict __attr, void *(*__start_routine) (void *), void *__restrict __arg) ;
__restrict __newthread : 获取创建成功的线程ID,该参数是一个输出型参数。
__restrict __attr: 用于设置创建线程的属性,传入NULL表示使用默认属性。
__start_routine: 该参数是一个函数地址,表示线程例程,即线程启动后要执行的函数。
__restrict __arg: 传给线程例程的参数。
返回值说明:
线程创建成功返回0,失败返回错误码。
创建一个线程
#include <stdio.h>
#include <pthread.h>
//C 和 C++ 程序设计语言中提供对 POSIX 操作系统 API 的访问功能的头文件的名称
#include <unistd.h>
void* Routine(void* arg)
{
char* msg = (char*)arg;
while (1){
printf("I am %s\n", msg);
sleep(1);
}
}
int main()
{
pthread_t tid;
void* addr = "new thread 1";
pthread_create(&tid, NULL, Routine, addr);
while (1){
printf("mian thread!\n");
sleep(2);
}
return 0;
}
效果如图
上面程序用sleep()函数让父线程等待子线程。但是线程中通常使用pthread_join函数,让父线程等待子线程执行完
3、线程的等待与退出
函数原型
This function is a cancellation point and therefore not marked with
__THROW. */
extern int pthread_join (pthread_t __th, void **__thread_return);
__th:线程标识符,即线程ID
__thread_return: 用户定义的指针,用来存储被等待线程的返回值。
返回值 : 0代表成功。 失败,返回的则是错误。
一个线程对应一个pthread_join()调用,对同一个线程进行多次pthread_join()调用属于逻辑错误。那么线程什么时候退出呢?
·在线程函数运行完后,该线程也就退出了
·线程内调用函数pthread_exit()主动退出
·当线程可以被取消时,通过其他线程调用pthread_cancel的时候退出
·创建线程的进程退出
·主线程执行了exec类函数,该进程的所有的地址空间完全被新程序替换,子线程退出
示例源码
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
static int count = 0;
void* Routine(void* arg)
{
int i;
for (i=0;i<5;i++) {
count++;
printf("The thread count is = %d\n",count);
sleep(1);
}
return NULL;
}
int main()
{
pthread_t tid;
pthread_create(&tid, NULL, Routine,NULL);
// 加入pthread_join后,主线程"main"会一直等待直到tid这个线程执行完毕自己才结束
pthread_join(tid,NULL);
// 如果没有join方法可以看看打印的顺序
printf("The count is = %d\n",count);
return 0;
}
效果如图
如果注释掉pthread_join
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
static int count = 0;
void* Routine(void* arg)
{
int i;
for (i=0;i<5;i++) {
count++;
printf("The thread count is = %d\n",count);
sleep(1);
}
return NULL;
}
int main()
{
pthread_t tid;
pthread_create(&tid, NULL, Routine,NULL);
// 加入pthread_join后,主线程"main"会一直等待直到tid这个线程执行完毕自己才结束
//pthread_join(tid,NULL);
// 如果没有join方法可以看看打印的顺序
printf("The count is = %d\n",count);
return 0;
}
效果如图