一、创建一个新的线程
1.头文件:<pthread.h>
2.函数:pthread_create(pthread_t *thread,const pyhread_attr_t *attr,void *(start_routine) (void ),void *arg);
名称 | 意义 |
---|---|
pthread_t | 相当于无符号长整型 |
*thread | 线程的ID |
const pyhread_attr_t *attr | 线程的属性,一半不管,默认 |
void *(start_routine) (void ) | 线程例程,实际上相当于创建线程的入口函数,本质是一个回调函数 |
void *arg | 函数的参数,有则传,没有设置为NULL |
3.执行新的线程,主进程仍然继续执行 | |
makefile文件: |
mythread:mythread.c
gcc -o $@ $^ -lpthread #引的是pthread这个库
.PHONY:clean
clean:
rm -f mythread
mythread文件:
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void *Routine(void *arg)
{
char *msg = (char*)arg;
while(1)
{
printf("%s\n",msg);
sleep(1);
}
}
int main()
{
pthread_t tid;
//创建线程
pthread_create(&tid,NULL,Routine,(void*)"thread 1"); //传thread 1参数
while(1)
{
printf("I am main thread!\n");
sleep(2);
}
return 0;
}
结果:
4.看是否属于一个进程,分别打印出线程与进程的id号,线程与进程的id号是一致的
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void *Routine(void *arg)
{
char *msg = (char*)arg;
while(1)
{
printf("%s:pid:%d,ppid:%d\n",msg,getpid(),getppid());
sleep(1);
}
}
int main()
{
pthread_t tid;
//创建线程
pthread_create(&tid,NULL,Routine,(void*)"thread 1"); //传thread 1参数
while(1)
{
printf("main thread:pid:%d,ppid:%d\n",getpid(),getppid());
sleep(2);
}
return 0;
}
5.ps -aL | head -1 && ps -aL | grep mythread(显示两个线程的PID一样)
-L:显示当前的轻量级进程
LWP:轻量级进程ID
OS调度的基本的时候,采用的是LWP,并非是PID!
Linux中,应用层的线程,与内核的LWP是1:1
6.创建一批线程
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
char *msg = (char*)arg;
while(1)
{
printf("%s: pid:%d,ppid:%d\n",msg,getpid(),getppid());
sleep(1);
}
}
int main()
{
pthread_t tid[5];
//创建线程
for(int i = 0; i < 5; i++)
{
char buffer[64];
sprintf(buffer,"thread %d",i); //把该输出到显示器上的内容输出到字符串中
pthread_create(&tid[i],NULL,Routine,(void*)buffer); //传thread 1参数
}
while(1)
{
printf("main thread:pid:%d,ppid:%d\n",getpid(),getppid());
sleep(2);
}
return 0;
}
7.显示自己线程ID:pthread_self()
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
char *msg = (char*)arg;
while(1)
{
printf("%s: pid:%d,ppid:%d,tid:%lu\n",msg,getpid(),getppid(),pthread_self());
sleep(1);
}
}
int main()
{
pthread_t tid[5];
//创建线程
for(int i = 0; i < 5; i++)
{
char buffer[64];
sprintf(buffer,"thread %d",i);
pthread_create(&tid[i],NULL,Routine,(void*)buffer); //传thread 1参数
printf("%s tid is:%lu\n",buffer,tid[i]);
}
while(1)
{
printf("main thread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());
sleep(2);
}
return 0;
}
注意:调用自己线程的ID:pthread _self(),和getpid()类似,但是类型为%lu,此时获得的是用户级原生线程库的线程ID,与LWP的关系是1:1
二、线程的等待
1.线程等待:phread_join(),默认等待以阻塞形式等待,若不等待,则可能会成为僵尸进程,造成内存泄漏
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
char *msg = (char*)arg;
int count = 0;
while(count < 5)
{
printf("%s: pid:%d,ppid:%d,tid:%lu\n",msg,getpid(),getppid(),pthread_self());
sleep(1);
count++;
}
return NULL;
}
int main()
{
pthread_t tid[5];
//创建线程
for(int i = 0; i < 5; i++)
{
char buffer[64];
sprintf(buffer,"thread %d",i);
pthread_create(&tid[i],NULL,Routine,(void*)buffer); //传thread 1参数
printf("%s tid is:%lu\n",buffer,tid[i]);
}
printf("main thread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());
//线程等待
for(int i = 0; i < 5; i++)
{
pthread_join(tid[i],NULL);
printf("thread %d[%lu] ... quit!\n",i,tid[i]);
}
return 0;
}
2.获取退出码
int pthread_join(pthread_t thread, void **retval)
retval:拿到被等待的线程的退出码,通常用来验证代码运行完毕,结果是否正确。
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
char *msg = (char*)arg;
int count = 0;
while(count < 5)
{
printf("%s: pid:%d,ppid:%d,tid:%lu\n",msg,getpid(),getppid(),pthread_self());
sleep(1);
count++;
}
return (void*)10;
}
int main()
{
pthread_t tid[5];
//创建线程
for(int i = 0; i < 5; i++)
{
char *buffer=(char*)malloc(64);
sprintf(buffer,"thread %d",i);
pthread_create(&tid[i],NULL,Routine,(void*)buffer); //传thread 1参数
printf("%s tid is:%lu\n",buffer,tid[i]);
}
printf("main thread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());
//线程等待
for(int i = 0; i < 5; i++)
{
void *ret = NULL;
pthread_join(tid[i],&ret); //获取退出码
printf("thread %d[%lu] ... quit! code:%d\n",i,tid[i],ret);
}
return 0;
}
另外:多线程需要考虑异常,但是做不到
三、线程的终止
1.为什么等待?
(1)已经退出的线程,其空间没有被释放,仍然在进程的地址空间内
(2)创建新的线程不会复用刚才退出线程的地址空间
2.正常终止的做法
(1).return XXX:在main内return,代表整个进程终止
(2).exit():也是整个进程全部终止
(3).终止某个线程:pthread_exit()
(4).pthread_cancel():取消某个线程,取消成功,退出码为-1
(5).main里面pthread_cancel(tid[0]) 取消其它线程(推荐),取消下标为0的线程
另外:
1.新线程可以取消主线程吗?可以,但是不推荐
2.一般情况下,线程必须被等待,就如同子进程必须被等待一样
3.线程可以不被join,也可以不用,但需要将线程进行分离
四、线程分离
pthread_detach()
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
pthread_detach(pthread_self()); //分离
char *msg = (char*)arg;
int count = 0;
while(count < 5)
{
printf("%s: pid:%d,ppid:%d,tid:%lu\n",msg,getpid(),getppid(),pthread_self());
sleep(1);
count++;
}
pthread_exit((void*)19); //线程退出码
// return (void*)10;
}
int main()
{
pthread_t tid[5];
//创建线程
for(int i = 0; i < 5; i++)
{
char *buffer=(char*)malloc(64);
sprintf(buffer,"thread %d",i);
pthread_create(&tid[i],NULL,Routine,(void*)buffer); //传thread 1参数
printf("%s tid is:%lu\n",buffer,tid[i]);
}
while(1){
printf("main thread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());
sleep(1);
}
/*
//线程等待
for(int i = 0; i < 5; i++)
{
void *ret = NULL;
pthread_join(tid[i],&ret); //获取退出码
printf("thread %d[%lu] ... quit! code:%d\n",i,tid[i],ret);
}
*/
return 0;
}
用户层如何得知对应的线程呢?
线程很多,需要被管理的,Linux不提供真正的线程,只提供LWP,意味着OS只需要对LWP内核执行流进行管理,那供用户使用的接口等其它数据由线程库pthread库来管理
pthread_t类型的线程ID,本质上就是一个进程地址空间上的一个地址。