1、线程概念:
线程就是一个正在运行的函数
一个进程里面至少会有一个线程
多个线程的内存是共享的
posix线程是一套标准,不是实现
openmp线程也是一种标准
线程标识:pthread_t(类型不清楚,但是在Linux下是整形数)
相关函数介绍:
pthread_equal():
pthread_equal - compare thread IDs
#include <pthread.h>
int pthread_equal(pthread_t t1, pthread_t t2);
Compile and link with -pthread.(编译或者链接的时候要加上-pthread)
写到makefile文件中
CFLAGS+=-pthread
LDFLAGS+=-pthread
pthread_self():(相当于进程中的get_pid)
pthread_self - obtain ID of the calling thread(获取当前线程的id
#include <pthread.h>
pthread_t pthread_self(void);
Compile and link with -pthread.
小的点:
ps axm(Linux可以看到进程的详细信息,可以看到–标识,就是线程)
ps ax -L(以Linux的形式查看进程和线程的关系)
Linux下以线程消耗进程号
会话是容器,承载进程组
进程组是容器,承载进程
进程是容器,承载线程
都有一种容器的概念
建议:不要把线程和信号大范围的混用
2、线程的创建
pthread_create():
pthread_create - create a new thread
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr(NULL表示默认),
void *(*start_routine) (void *)(函数,就是创建出的线程函数), void *arg)(函数的参数,若想传多个参数就使用结构体);
Compile and link with -pthread.
返回值
On success, pthread_create() returns 0; on error, it returns an error
number, and the contents of *thread are undefined.(只能用strerror来报错
例子:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
static void *func(void *p)
{
puts("Thread is working!");
return NULL;
}
int main()
{
pthread_t tid;
int err;
puts("Beigin!");
err=pthread_create(&tid,NULL,func,NULL);
if(err)
{
fprintf(stderr,"pthread_create():%s\n",strerror(err));
exit(1);
}
puts("End!");
exit(0);
}
运行结果:
Beigin!
End!
看不到线程运行的原因:线程的调度取决于调度器的调度策略,在虚拟机里面不能多核运行线程来不及调度,进程就结束。(在不同的主机上运行结果不同)
线程终止
3种方式: 1)线程从启动例程返回,返回值就是线程的退出码。
2)线程被同一进程中的其他的线程取消
3)线程调用调用pthread_exit()函数(相当于进程阶段的exit()函数)
pthread_exit():
pthread_exit - terminate calling thread
#include <pthread.h>
void pthread_exit(void *retval);
Compile and link with -pthread.
例子:
static void *func(void *p)
{
puts("Thread is working!");
pthread_exit(NULL);//线程栈的清理用到
}
线程收尸
pthread_join();(相当于进程中的wait())
pthread_join - join with a terminated thread
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
第二项若是空,就表示只收尸,不关注状态
若是想把收尸的状态来加以查看的话,给一个void*类型变量的地址(一级指针的地址)
Compile and link with -pthread.
例子:
将上面的main函数中增加pthread_join()函数的使用
int main()
{
pthread_t tid;
int err;
puts("Beigin!");
err=pthread_create(&tid,NULL,func,NULL);
if(err)
{
fprintf(stderr,"pthread_create():%s\n",strerror(err));
exit(1);
}
pthread_join(tid,NULL);
puts("End!");
exit(0);
}
运行结果:(这个结果是一定的)
一定要等到线程运行完,才可以收尸,所以一定会运行线程。
Beigin!
Thread is working!
End!
栈的清理
pthread_cleanup_push():
pthread_cleanup_pop():(和钩子函数很像,或者可以想象栈的压和出)
pthread_cleanup_push():
pthread_cleanup_pop():
pthread_cleanup_push, pthread_cleanup_pop - push and pop thread cancel‐
lation clean-up handlers
#include <pthread.h>
void pthread_cleanup_push(void (*routine)(void *),
void *arg);
void pthread_cleanup_pop(int execute);
pop函数的参数若为真,说明函数要被调用,反之不被调用
Compile and link with -pthread.
例子:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
static void cleanup_func(void *p)
{
puts(p);
}
static void *func(void *p)
{
puts("Thread is working!");
pthread_cleanup_push(cleanup_func,"cleanup:1");
pthread_cleanup_push(cleanup_func,"cleanup:2");
pthread_cleanup_push(cleanup_func,"cleanup:3");
puts("push over");
pthread_cleanup_pop(1);
pthread_cleanup_pop(1);
pthread_cleanup_pop(1);
pthread_exit(NULL);
}
int main
{
pthread_t tid;
int err;
puts("Beign");
err=pthread_create(&tid,NULL,func,NULL);
if(err)
{
fprintf(stderr,"pthread_create():%s\n",strerror(err));
exit(1);
}
pthread_join(tid,NULL);
puts("End");
exit(0);
}
运行结果:
Beign
Thread is working!
push over
cleanup:3
cleanup:2
cleanup:1
End
注意:push和pop一定是成对出现的,这两个不是函数,而是宏,可以用gcc .c文件 -E来验证,若是少了pop预处理的结果就会
少一个大括号匹配。若pop的参数为0,则表示只弹栈,而不去调用。比如上面的程序,若只有第一个pop参数是1,则结果只会
包含cleanup:3。pop可以放在任何的位置。若是放在pthread_exit后面,执行的时候,由于看不到后面的参数,默认都为1.