(百度百科来凑数的,哈哈~~~) 线程:有时被称为轻量级进程,是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
创建线程:
创建线程函数:
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
参数说明:1. thread:pthread_t类型的指针 ,用来返回所创建的线程的ID (非负数)
2.attr :指定线程的属性。默认为NULL 。稍后介绍
3.start_routine:线程创建后所要调用的函数,这是一个函数指针。
插曲( 指针函数与函数指针的简单区别):
指针函数:int *f(int a, int b);
函数指针:int (*f)(int a, int b);
说明: 函数指针就是用括号把你的函数名括起来,加一个*号。指针函数就是加一个*号
4.arg:传递给线程函数的参数 。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
typedef struct {
int a;
int b;
}TT ;
void *creat_pthread(void *arg)
{
TT *p = (TT *)arg;
pthread_t newthid ;
int i;
newthid=pthread_self() ;
printf("the new pthread ID is %u \n",newthid) ;
for(i= 0 ;i< (p->a) ; i++ )
printf("---------------------------%d\n",i );
return NULL ;
}
int main(void)
{
TT *p = (TT *)malloc(sizeof(TT)) ;//注意开辟空间,我就被坑在这里了@~@
pthread_t thid ;
int n ,i;
p->a= 100 ;
p->b= 30 ;
printf("%d %d\n",p->a,p->b);
printf("the main pthread ID is %u \n",pthread_self()) ;
if(pthread_create(&thid ,NULL ,creat_pthread ,(void *)p) != 0)
{
printf("creat pthread is failed !! \n");
exit(-1);
}
for(i= 0;i< 100;i++)
printf("+++++++++++++++++++++++%d\n",i);
sleep(5);
exit(0);
}
执行结果:
注意事项:
1.如果调用函数返回一个void 指针,则不需要强转。
2. 参数arg ,必须强转为void * 的类型,然后再在调用函数中转回来即可
3.传递多个参数时,必须申明一个结构体来包含所有的参数,然后再传入线程函数其实也是一个封装的思想了
4.结果也说明,线程执行顺序是不确定的,是由CPU 的调度算法(时间片的分配)所决定的 。
一些简单函数的说明:
pthread_t pthread_self(void);//取得本线程ID
int pthread_equal(pthread_t t1, pthread_t t2);//判断两个线程ID 是否指向同一个线程
int pthread_once(pthread_once_t *once_control,void (*init_routine)(void)); //保证init_routine 线程函数在进程中只执行一次
线程属性 :
该结构体是
typedef struct
{
int detachstate; 线程的分离状态
int schedpolicy; 线程调度策略
struct sched_param schedparam; 线程的调度参数
int inheritsched; 线程的继承性
int scope; 线程的作用域
size_t guardsize; 线程栈末尾的警戒缓冲区大小
int stackaddr_set;
void * stackaddr; 线程栈的位置
size_t stacksize; 线程栈的大小
}pthread_attr_t;
参数说明:
schedpolicy:线程调度策略,只要有三种:(1)正常非实时。(2):实时,轮转。(3):实时,先入先出。(后两种调度只对root 用户有效)
schedparam :一个struct sched_param 结构体,其中有一个sched_priority 表示线程优先级,只有当调度策略为实时才有效,缺省为0
scope:线程优先级有效范围
线程终止(两种):
1.return 返回
2. 使用pthread_exit()函数:
#include <pthread.h>
void pthread_exit(void *retval);
两种特殊情况:
1.在主线程中线程过早返回或者是调用exit 函数,则整个进程都会终止。就会导致所有的线程终止 。
2.在主线程中线程调用pthread_exit函数退出,进程不会结束,直到所有线程结束,进程才会结束
资源释放:
有些资源必须在一段时间内被一个线程所持有,其他线程使用资源时提出申请,也就是我所说的厕所的问题。现在我们假设一种情况,如果一个线程在终止时并没有释放资源,那么其他线程也无法使用,这就会导致死锁!!那么linux 该如何解决这个问题呐???
linux 系统提供了一对函数用于主动释放资源
#include <pthread.h>
1.void pthread_cleanup_push(void (*routine)(void *),
void *arg);
2.void pthread_cleanup_pop(int execute);
说明:1.这两个函数的调用之间的程序段中的终止动作都会执行pthread_cleanup_push所指定的清除函数。
2.pthread_cleanup_push带有一个{ ,pthread_cleanup_pop带有一个},因此这两个函数必须成对出现,且必须位于程序的同一段代码中才能编译通过。
线程间的同步(相当于进程中的wait 函数)
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
说明:1.pthread_join用来等待一个线程的结束,调用pthread_join的线程被挂起,回收所等待线程的资源。
2.一个线程只允许一个线程使用pthread_join来等待
3.被等待的线程应该处于”join”的状态,而非死亡状态(DETACHED)
4.为避免内存泄漏,因此所有的线程终止时,必须处于两种情况之中(1.死亡状态(DETACHED)2.使用pthread_join和回收资源)
小示例:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
int *creat_pthread(int *n )
{
pthread_t newthid ;
int i;
newthid=pthread_self() ;
printf("the new pthread ID is %d \n",newthid) ;
for(i= 0 ;i< *n ;i++)
printf("------------------------%d\n",i );
pthread_exit((void *)-100);
}
int main(void)
{
pthread_t thid ;
int n ,i;
int status ;
printf("main pthread ID is %d \n",pthread_self());
printf("please input the n : ");
scanf("%d",&n);
if(pthread_create(&thid ,NULL ,(void *)creat_pthread ,&n) != 0)
{
printf("creat pthread is failed !! \n");
exit(-1);
}
pthread_join(thid,(void *)&status);
printf("the new pthread's exit number is %d \n",status);
exit(0);
}