堆栈
线程包含线程ID,寄存器的值栈。
堆属于整个进程, 栈属于线程级别的。
一个进程可能出现多个栈,线程之间的栈是独立的,但是可以互相访问的。调度优先级,等属于线程的。
errno属于线程的,在线程栈中
CPU同一时间只能执行一条指令。进程内所有的信息对于线程都是共享的,包括执行代码,全局变量,和堆内存,栈以及文件描述符。
线程标识:
进程用pid_t表示,是一个unsigned int
线程ID用pthread_t表示,pthread_t不能把它当整数处理。
线程可以通过pthread_self()函数获得自身的线程ID。
线程创建:
-一个进程最少有一个线程,单线程方式启动。。
在进程中只有一个控制线程,捕捉信号函数最好写在控制线程中,否则程序会别的异常复杂。
程序开始运行的时候每个进程只有一个线程。它以当线程的方式启动。在创建多个线程以前,进程的行为,与传统的进程没有区别。
gcc 在链接的时候需要增加-lpthread选项。-lpthread 表示链接libpthread.so库。
创建一个线程调用pthread_create函数。
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
第一个参数:线程id
第二个参数:一般为NULL 线程的一些属性
第三个参数:线程回调函数
第四个参数:传递给线程回调函数的参数
创建成功返回零,失败返回错误码。errno
ps -eLF 查看线程。
线程退出
1. 在启动函数中返回,返回值是线程退出码
2.线程可以在同一个进程中的线程取消。
3.调用exit();函数
4.调用pthread_exit函数。
线程调用:
线程与线程调用时异步并行随机的。
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval); 类似wait();
第一个参数ID号,第二个是无类型的二级指针。
挂起当前进程,直达参数thread指定的线程终止为止。
如果另一个线程返回不是NULL,则保持在retval地址中。
一个线程所使用的内存资源在应用pthread_join调用之前不会被重新分配,所以对于每个线程必须调用一次pthread_join函数。
例子:
/////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<unistd.h>
#include<sys/types.h>
#include<errno.h>
#include<signal.h>
#include <pthread.h>
#include<string.h>
#include<malloc.h>
void* func12(void *num)
{
int p = *(int*)num;//得到num[]数组的值
free(num);
while(1)
{
printf("thread%d start..
" , p );
sleep(1);
break;
}
int *a ;
a=malloc(sizeof(int));
*a = 100;
return a;//代表线程已经结束了。
}
void* func3(void *num)
{
while(1)
{
printf("thread3 start..
" );
sleep(1);
// break;
}
pthread_exit(NULL);//线程可以被同一进程中的其他线程取消掉。
return NULL;//这一句就不会执行啦。。
}
void creat_thread()
{
pthread_t thr1 ,thr2;
//int num[2];//这是局部变量,函数执行完成后,内存会释放掉。所以加static,或malloc
//num[0] = 1;
//num[1] = 2;
int *num1,*num2;
num1 = (int*)malloc(sizeof(int));
num2 = (int*)malloc(sizeof(int));
*num1 = 1;
*num2 = 2;
if( pthread_create(&thr1 , NULL , func12 , num1) )//返回非零表示成果,传递num[]值 同时执行func函数
{
printf("thread1 error :%s
" , strerror(errno));
}
if( pthread_create(&thr2 , NULL , func12 , num2) )//传递num[]值 同时执行func函数
{
printf("thread2 error :%s
" , strerror(errno));
}
int *p = NULL;
pthread_join(thr1 , (void*)&p);//主线程挂起,等待thr1线程的结束
pthread_join(thr2 , NULL);//主线程挂起,等待thr2线程的结束
printf("p= %d" , *p);
free(p);
}
//main函数里面的栈与线程中的栈是可以相互访问的。
int main(void)
{
puts("pthread start!");
pthread_t thr3 ,thr4,thr5,thr6 ,thr7;
creat_thread();
if( pthread_create(&thr3 , NULL , func3 , NULL) )//线程函数func3
{
printf("thread2 error :%s
" , strerror(errno));
}
return EXIT_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////////////////
线程分离
#include <pthread.h>
int pthread_detach(pthread_t thread);
一旦线程成为分离线程后,就不能再使用pthread_join了
可分离线程的使用:
1.主线程不需要等待子线程。
2.主线程不关心子线程的返回码
#include <pthread.h>
int pthread_cancel(pthread_t thread);
另一个线程中终止另外的线程。
//////////////////////////////////////////////////////////////////////////////
/*
============================================================================
Name : thread.c
Author :
Version :
Copyright : Your copyright notice
Description : Hello World in C, Ansi-style
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<unistd.h>
#include<sys/types.h>
#include<errno.h>
#include<signal.h>
#include <pthread.h>
#include<string.h>
#include<malloc.h>
void* func3(void *num)
{
while(1)
{
printf("thread3 start..
" );
}
return NULL;//这一句就不会执行啦。。
}
void* func2(void *num)
{
pthread_t id = *(pthread_t*)num;
sleep(5);
printf("thread2 start..
" );
pthread_cancel(id);
printf("thread2 end..
" );
return NULL;//这一句就不会执行啦。。
}
void* func1(void *num)
{
printf("thread1 start..
" );
while(1)
{
sleep(1);
printf("thread1 living..
" );
}
printf("thread1 end..
" );
return NULL;//这一句就不会执行啦。。
}
//main函数里面的栈与线程中的栈是可以相互访问的。
int main(void)
{
puts("pthread start!");
pthread_t thr1,thr2 , thr3 ;
if( pthread_create(&thr1 , NULL , func1 , NULL) )//线程函数func3
{
printf("thread1 error :%s
" , strerror(errno));
}
if( pthread_create(&thr2 , NULL , func2 , &thr1 ) )//线程函数func3
{
printf("thread2 error :%s
" , strerror(errno));
}
if( pthread_create(&thr3 , NULL , func3, NULL ) )//线程函数func3
{
printf("thread3 error :%s
" , strerror(errno));
}
pthread_detach(thr3);//设置为可分离线程 使用场景:1.主线程不需要等待子线程,也不关心子线程的返回码 ,使用pthread_join(thr3 ,NULL);已经没有用了。
pthread_join(thr1,NULL);
pthread_join(thr2 , NULL);
return EXIT_SUCCESS;
}
//////////////////////////////////////////////////////////////////////////////////
#include <pthread.h>
int pthread_equal(pthread_t t1, pthread_t t2);
比较2个线程id是否相同,相同返回非零。不同返回0.。不能像进程那样直接if(pid1 == pid2)而必须使用此函数来判断线程id是否相等
线程属性:
pthread_creat函数第二个参数,以前调用pthread_create传入的attr参数都是空指针,而不是指向pthread_attr_t结构的指针,
可以使用pthread_attr_t结构修改线程默认属性,并把这些属性与创建的线程联系起来。
可以使用pthread_attr_init函数初始化pthread_attr_t结构。
调用pthread_attr_init以后,pthread_arrt_t的结构所包含的内容就是操作系统实现支持线程所有属性的
默认值。如果要修改其中个别属性的值,需要调用其他函数。
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
pthread_attr_init初始化pthread_attr_t结构。
int pthread_attr_destroy(pthread_attr_t *attr);
pthread_attr_destroy函数释放attr内存空间。
pthread_attr_t结构对于应用程序来讲是不透明的,应用程序不需要了解有关结构的内部组成。
pthread_detach在创建线程的时候就指定线程属性为detach,而不是创建以后再去修改线程的属性。
#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
函数pthread_attr_setdetachstate把线程属性设置为下面合法值之一
PTHREAD_CREATE_DETACHED 设置线程为分离状态
PTHREAD_CREATE_JOINABLE 设置线程为正常状态 默认状态
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
///////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<unistd.h>
#include<sys/types.h>
#include<errno.h>
#include<signal.h>
#include <pthread.h>
#include<string.h>
#include<malloc.h>
void*fun1(void*)
{
while(1)
{
printf("1111");
}
}
void *fun2(void*)
{
while(1)
{
printf("2222");
}
}
//main函数里面的栈与线程中的栈是可以相互访问的。
int main(void)
{
pthread_attr_t attr;
pthread_t thr1,thr2 ;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr , PTHREAD_CREATE_DETACHED );//设置线程属性是可分离的。
if( pthread_create(&thr1 , &attr , func1 , NULL) )//线程函数func1
{
printf("thread1 error :%s
" , strerror(errno));
}
if( pthread_create(&thr2 , NULL , func2 , &thr1 ) )//线程函数func2
{
printf("thread2 error :%s
" , strerror(errno));
}
pthread_attr_destory(&attr);
pthread_join(thr1,NULL);//已经没用了。
return EXIT_SUCCESS;
}
////////////////////////////////////////////////////////////////////////////