线程控制
创建线程
int pthread_create(pthread_t *thread,const pthread_attr_t *attr, \
void*(*start_routine)(void*),void *arg);
第一个参数:返回线程id
第二个参数:设置线程属性默认NULL
第三个参数:函数地址,线程启动后执行的函数
第四个参数:传给线程启动函数的参数
成功:返回0 失败:返回错误码
#include
#include
#include
#include
#include
void *rout(void *_val)
{
printf("I am %s pid is : %d , tid is : %u\n",(char*)_val,(int)getpid(),(unsigned long long)pthread_self());
return NULL;
}
int main()
{
pthread_t tid;
int ret;
ret=pthread_create(&tid,NULL,rout,"pthread1");
if(ret!=0)
{
fprintf(stderr, "pthread_create: %s\n",strerror(ret));
exit(EXIT_FAILURE);
}
printf("I am main thread pid is : %d , tid is %u\n",(int)getpid(),(unsigned long long)pthread_self());
sleep(1);
return 0;
}
由上例可以看出pthread_t 类型是一个地址值
属于同一进程的多个线程调用getpid()可以得到相同的进程号
调用pthread_self()得到的线程号各不相同。
线程终止
#include
void pthread_exit(void *retval);
pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。
取消线程
#include
int pthread_cancel(pthread_t thread);
线程是允许被取消的,退出结果为-1,线程自己取消自己(不推荐)退出结果为0。
线程等待
为什么要线程等待?
main函数执行的线程称为主线程,多线程的执行顺序由线程调度决定
主线程必须回收其他线程,否则就会产生类似僵尸进程的状况(内存泄漏)。
#include
int pthread_join(pthread_t thread, void **retval);
返回值:成功返回0,失败返回错误码。
参数thread:线程号,即要等待线程的tid
参数retval:要等待线程的退出码(输出型参数)
举例
#include
#include
#include
#include
#include
void *thread1(void *val1)
{
printf("thread 1 returning .....\n");
printf("%s:pid is %d,tid is %u\n",(char*)val1,getpid(),pthread_self());
return (void*)0; //线程终止方式1,用return返回
}
void *thread2(void *val2)
{
printf("thread 2 exiting .....\n");
printf("%s:pid is %d,tid is %u\n",(char*)val2,getpid(),pthread_self());
pthread_exit ((void*)2);//线程终止方式2,调用pthread_exit
}
void *thread3(void *val3)
{
printf("%s:pid is %d,tid is %u\n",(char*)val3,getpid(),pthread_self());
while(1)
{
printf("thread 3 is running....\n");
sleep(1);
}
//线程终止方式3,用pthread_exit退i出
}
int main()
{
pthread_t tid1;
pthread_t tid2;
pthread_t tid3;
void *ret;
//thread 1 return
pthread_create(&tid1,NULL,thread1,"thread1"); //线程1创建
pthread_join(tid1,&ret); //wait 线程1 ret指向单元存放thread1的返回值
printf("thread1 return return code:%d\n",(int)ret);
//thread 2 exit
pthread_create(&tid2,NULL,thread2,"thread2"); //线程2创建
pthread_join(tid2,&ret); //wait线程2 ret指向单元存放传给pthread_exit的参数
printf("thread exit, exit code:%d\n",(int)ret);
//thread 3 pthread_cancel
pthread_create(&tid3,NULL,thread3,"thread3"); //线程3创建
sleep(3);
pthread_cancel(tid3); //线程3被其他线程用pthread_cancel取消了
pthread_join(tid3,&ret); //wait 线程3 ret指向单元存放PTHREAD_CANCELED
if(ret==PTHREAD_CANCELED)
{
printf("thread 3 cancel ,cancel code id %d\n",(int)ret);
}
printf("main thread run: pid is %d , tid is %u\n", getpid(),pthread_self());
return 0;
}
通过上图可以发现为什么3个线程的pid和tid都是相同的呢?
是pid实际上是主线程的进程号
线程号的线程的唯一标识符,为什么不同的线程,线程号是相同的?
调用过线程等待函数之后主线程就会回收其资源,其中当然也包括线程id,,当线程1回收之后,我们紧接着创建了线程2,系统会优先选择刚刚回收的1号线程id来分配给线程2,当线程2终止等待之后,此线程号再次被回收利用,进而分配给线程3,这就是为什么我们看到不同的3个线程拥有同一个tid了。
线程的属性
线程的两种属性:可结合性和可分离性。
默认线程的创建是可结合的
一个分离的线程是不能被其他线程回收或杀死的,它的存 储器 资源在它终止时由系统自动释放。
由于调用pthread_join后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此。改善方法:
1>可以在子线程中加入代码:
pthread_detach(pthread_self())
2>父线程调用
pthread_detach(thread_id)(非阻塞,可立即返回)
这将该子线程的状态设置为分离的(detached),detached),如一来,该线程运行结束后会自动释放所有资源。
#include
#include
#include
#include
#include
void *thread_run(void* arg)
{
pthread_detach(pthread_self());
printf("%s\n",(char*)arg);
return NULL;
}
int main(void)
{
pthread_t tid;
if(pthread_create(&tid,NULL,thread_run, "thread1 run...")!=0)
{
printf("create thread error\n");
return 1;
}
int ret=0;
sleep(1);
if(pthread_join(tid,NULL)==0)
{
printf("pthread wait success!\n");
ret=0;
}
else
{
printf("pthread wait failed\n");
ret=1;
}
return ret;
}
线程启动时执行程序thread_run函数进行线程分离,主线程sleep1秒,然后主线程执行等待函数,因为线程已经被分离了,等待函数无法对其资金进行回收,所有等待失败。