线程包含了表示进程执行环境所必要的信息,包括线程标识符,一组寄存器的值,栈,调度优先级和策略,信号屏蔽字,errno变量及线程私有数据,进程所有的信息对该进程内所有线程都是共享的,包括可执行程序文本,程序全局内存及堆内存,栈和文件描述符。在Linux创建新线程的时候,都会有一个控制线程用于控制新线程的相应工作,被称为主线程或控制线程。
目录
线程标识符:
与进程标识符类似,每一个线程都有一个线程标识符唯一表示,其用一个数据结构类型pthread_t来表示,Linux提供两个函数用于对线程标识符的操作:
#include <pthread.h>
pthread_t pthread_self(void);
用于获取线程自身的线程标识符。
#include <pthread.h>
int pthread_equal(pthread_t tid1,pthread_t tid2);
两个参数分别是需要比较的线程标识符,相等返回一个非0值,否则返回0。
线程的属性:
通过一个结构体pthread_attr_t来定义的:
typedef struct
{
int datachstate; //线程拆卸状态
int schedpolicy; //线程调度策略
struct sched_param schedparam; //调度参数
int inheritsched; //继承性
size_t guardsize;
int stzckaddr_set;
void * stackaddr; //堆栈位置
size_t stacksize; //堆栈大小
}
pthread_attr_t;
线程控制相关函数:
#include <pthread.h>
int pthread_creat(pthread_t *thread,pthread_attr_t*attr,void*(*start_routine)(void*),void*arg);
成功返回0,出错返回错误编号;
thread是返回的线程标识符,attr线程属性,一般设为NULL,start_routine线程运行的函数,arg是start_routine函数的参数。
creat_pthread.c如下:
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
pthread_t ntid;
void prints(const char *s)
{
pid_t pid;
pthread_t tid;
pid=getpid();
tid=pthread_self(); //获取线程标识符
printf("%s pid:%d tid:%lu\n",s,pid,tid);
}
void* thread_fun(void* arg)
{
prints("new thread:");
return (void*)0;
}
int main()
{
int err;
err=pthread_create(&ntid,NULL,thread_fun,NULL); //创建新线程
if(err!=0)
{
printf("error : %s\n",strerror(err));
return -1;
}
prints("main thread:");
sleep(1);
return 0;
}
用gcc编译时,有参数 -lpthread ,结果如下:
#include <pthread.h>
void pthread_exit(void * retval);
retval表示线程终止状态,可以由用户指定传递函数一个参数,pthread_exit执行完毕后调用该参数来获取线程退出 状态。
#include <pthread.h>
int pthread_join(pthread_t thread,void **reval);
成功返回0,出错返回非0.thread为线程标识符,用于指定要等待其终止的线程,reval存放其他线程的返回值。
join_thread.c如下:
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
void thread_fun(char *ptr)
{
int i;
for(i=0;i<5;i++)
{
printf("%d--%s\n",i,ptr);
}
}
int main()
{
void*reval;
pthread_t tid1,tid2;
char *ma1="this is first thread\n";
char *ma2="this is second thread\n";
pthread_create(&tid1,NULL,(void*)&thread_fun,(void*)ma1);
pthread_create(&tid2,NULL,(void*)&thread_fun,(void*)ma2);
pthread_join(tid1,&reval);
pthread_join(tid2,&reval);
return 0;
}
主线程等待创建的两个新线程执行完毕后才会结束。结果如下:
#include <pthread.h>
int pthread_cancel(pthread_t thread);
成功返回0,出错返回错误编号。thread要取消线程的标识符。用于同一进程内取消另一个线程运行。当调用该函数取消一个线程之后,需要调用相应的函数对进程退出之后的环境进行清理,这些函数被称为线程清理处理程序,函数原型如下:
#include <pthread.h>
void pthread_cleanup_push(void (*routine)(void*),void*arg);
void pthread_cleanup_pop(int excute);
pthread_cleanup_push函数将子程序 routine和参数arg压入当前线程处理程序的堆栈,在当前线程调用pthread_exit或者通过pthread_cancel终止执行时,堆栈中处理程序将按照压栈时相反的顺序依次调用;
pthread_cleanup_pop函数从线程处理程序中弹出栈顶的程序并执行它。
在linux中,线程一般有分离和非分离两种状态,默认是非分离的,父线程维护子线程的某些信息并等待子线程结束,如果没用join情形下,子线程结束时,父线程维护的信息可能没来得及释放。而分离线程,不会有其他线程等待他结束,它运行结束后,线程终止,资源得到释放,可以调用pthread_detach函数实现分离线程。
#include <pthread.h>
int pthread_detach(pthread_t thread);
线程之间的同步:
互斥锁:
为实现多个线程并发执行时互斥和同步访问共享资源时,采用的一种机制,如果一个线程已经锁定了一个互斥锁,其他线程会被挂起等待。
#include <pthread.h>
int pthread_mutex_init (pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr);
成功返回0,失败返回错误编号。该函数函数初始化互斥锁,参数mutex是函数返回的指向互斥锁变量,mutexattr互斥锁属性,可以设置为NULL。
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex)
成功返回0,失败返回错误编号,该函数用来注销一个互斥锁。
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
成功返回0,出错返回非零值,用pthread_mutex_lock()加锁时,如果mutex已经被锁住,当前尝试加锁的线程就会阻塞,直到互斥锁被其他线程释放。当pthread_mutex_lock()函数返回时,说明互斥锁已经被当前线程成功加锁。pthread_mutex_trylock函数则不同,如果mutex已经被加锁,他将立即返回,返回的错误码为ebusy,而不是阻塞等待。两者对已加锁的处理不同。
#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex)
成功返回0,出错返回非零值,该函数用于解锁参数mutex指向的互斥锁。
如下,实现两个线程之间同步操作:lock_thread.c
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <stddef.h>
char buffer[256];
pthread_mutex_t mutex;
int retflag=0;
int buin=0;
void thread_fun();
int main()
{
pthread_t tid;
pthread_mutex_init(&mutex,NULL);
pthread_create(&tid,NULL,(void*)&thread_fun,NULL);
int i=0;
while(1)
{
if(i==5)
{
retflag=1;
return 0;
}
pthread_mutex_lock(&mutex);
if(buin==0)
{
sprintf(buffer,"this is %d\n",i++);
buin=1;
}
pthread_mutex_unlock(&mutex);
}
return 0;
}
void thread_fun()
{
while(1)
{
if(retflag)
return ;
pthread_mutex_lock(&mutex);
if(buin==1)
{
buin=0;
printf("%s",buffer);
}
pthread_mutex_unlock(&mutex);
}
return;
}
上述代码主线程向buffer写入数据,新线程读取打印数据,为保证同步操作,采用互斥锁使得buffer同一时间只能被一个线程访问,防止出现为写入数据就被读取的情况。