一,多线程之线程的概念
1,掌握先线程的基本概念,了解线程的优势
进程:资源分配的最小单位。
由于进程是资源的所有者;创建,撤消和切换资源都由进程来进行,涉及较大的时空开销以及多处理机(SMP)的出现。又因为一个进程包含多个线程这些线程可以共享同时享有该进程的资源,故引入线程。
线程:称为轻量级进程,程序执行的最小单位,系统独立调度和分配cpu的基本单位。
线程的优势:1)可同时共享一个资源(cpu),占用系统较少资源。2)模块化的编程(一个线程执行一个事件)更加清楚的表达程序中独立事件的关系,结构清晰。3)实现多处理器中开发程序的并行性。4)在等待IO操作时,程序可以执行其他操作,提高并发性。
2,重点难点:并发,并行,同步,异步
并发:假并行,看起来同时发生,实则是cpu在快速在不同进程间切换运行。
并行:同一时刻,不同进程在不同处理器上同时运行,真正的同时发生。
3,并发和并行的区别
区别:并发假同时发生,并行真正的同时发生。
二,线程的创建
1,学会利用pthred_create函数创建线程,及掌握pthread_create的参数意义。
创建线程ID:
例子1:获取线程id
#include"stdio.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"
int main()
{
pid_t pid;//进程id
pthread_t tid;//线程id
pid=getpid();//获取进程的id
tid=pthread_self();//获取线程id
printf("pid=%d tid=%x\n",pid,tid);
}
pthread_create()函数的解析:
【注】查看错误的原因解释目录:cat /usr/include/asm-generic/errno.h
例子2:创建线程,
#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include<pthread.h>
#include"stdlib.h"
#include"string.h"
void print_id(char *arg)
{
pid_t pid;//进程id
pthread_t tid;//线程id
pid=getpid();//获取进程的id
tid=pthread_self();//获取线程id
printf("%s pid=%d tid=%ld\n",arg,pid,tid);
}
void *pthread_fun(void *arg)
{
print_id(arg);
return (void*)0;
}
int main()
{
pthread_t newtid;
int errno;
errno=pthread_create(&newtid,NULL,pthread_fun,"new thread");
if(errno!=0)
{
printf("create new thread failure errno=%d\n",errno);
return errno;
}
print_id("main thread");//主线程先调用print_id函数,子线程后线程调用print_id函数
sleep(1);//主线程执行完后睡眠1秒,确保子线程执行完再结束。
return 0;
}
编译文件:gcc -o pthread pthread_create.c -pthread
运行结果如下:
可见主线程先打印出主线程所在进程的进程pid和线程tid,然后子线程才打印出自己的所在进程的进程pid和线程tid。因为主线程和子线程同属一个进程,所以他们的进程pid相同。
例子3,将例子2中的启动函数的参数改为一个结构体,将结构体作为启动函数的参数传给启动函数pthread_fun;同样是实现例子2的打印功能;将例子2 的代码修改如下:
#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include<pthread.h>
#include"stdlib.h"
#include"string.h"
typedef struct PT_TH_ID
{
int pid;
long int tid;
}PT_TH_ID;
void print_id(PT_TH_ID *p)
{
p->pid=getpid();
p->tid=pthread_self();
printf(" pid=%d tid=%ld\n",p->pid,p->tid);
}
void *pthread_fun(void *arg)
{
print_id(arg);
return (void*)0;
}
int main()
{
PT_TH_ID *p;
pthread_t newtid;
int errno;
errno=pthread_create(&newtid,NULL,pthread_fun,p);
if(errno!=0)
{
printf("create new thread failure errno=%d\n",errno);
return errno;
}
print_id(p);//主线程先调用print_id函数,子线程后线程调用print_id函数
sleep(1);//主线程执行完后睡眠1秒,确保子线程执行完再结束。
return 0;
}
运行结果如下:
2,掌握线程的生命周期。
1)在一个进程中主线程一旦结束,尽管其他子线程还没结束,整个进程将会结束。这样会造成不可想的后果,一般一个进程中main()函数作为主线程,main一旦结束进程就会结束.为了避免这个后果,主线程main()中可以调用pthread_exit()函数,该函数作用是等所有线程结束时进程才会结束。
2)主线程随进程的创建而创建,其他线程通过pthread_create来创建
3)[注]新线程可能在当前线程从函数pthread_create返回之前已经运行结束了,甚至已经运行完毕了。
例子4:验证主线程结束进程就结束,子线程就无法执行。对例子2修改,在子线程启动函数里加sleep(2);
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"
void print_id(char *arg)
{
pid_t pid;//进程id
pthread_t tid;//线程id
pid=getpid();//获取进程的id
tid=pthread_self();//获取线程id
printf("%s pid=%d tid=%ld\n",arg,pid,tid);
}
void *pthread_fun(void *arg)
{
sleep(2);//睡眠2秒
print_id(arg);
return (void*)0;
}
int main()
{
pthread_t newtid;
int errno;
errno=pthread_create(&newtid,NULL,pthread_fun,"new thread");
if(errno!=0)
{
printf("create new thread failure errno=%d\n",errno);
return errno;
}
pid_t pid;//进程id
pthread_t tid;//线程id
pid=getpid();//获取进程的id
tid=pthread_self();//获取线程id
printf("main thread pid=%d tid=%ld\n",pid,tid);//打印主线程的pid和tid
return 0;
}
编译并运行,结果如下:
入结果,主线程打印出主线程的pid和tid后,进程就结束了;并没有等到子线程执行。
在例子4主线程main结束前加pthread_exit();可解决这个情况.代码如下;
#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"
void print_id(char *arg)
{
pid_t pid;//进程id
pthread_t tid;//线程id
pid=getpid();//获取进程的id
tid=pthread_self();//获取线程id
printf("%s pid=%d tid=%ld\n",arg,pid,tid);
}
void *pthread_fun(void *arg)
{
sleep(2);//睡眠2秒
print_id(arg);
return (void*)0;
}
int main()
{
pthread_t newtid;
int errno;
int *rval;
errno=pthread_create(&newtid,NULL,pthread_fun,"new thread");
if(errno!=0)
{
printf("create new thread failure errno=%d\n",errno);
return errno;
}
pid_t pid;//进程id
pthread_t tid;//线程id
pid=getpid();//获取进程的id
tid=pthread_self();//获取线程id
pthread_exit(rval);//参数系统自动回填,不用初始化。
printf("main thread pid=%d tid=%ld\n",pid,tid);//打印主线程的pid和tid
return 0;
}
结果如下:
可见子线程在sleep(2)后,打印出子线程pid和tid后,进程才结束的。
3,如何给新线程传递多个参数,线程有几种基本状态?
线程的四个基本状态:
线程的回收: