一、创建一个新的线程
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,本质上就是一个进程地址空间上的一个地址。










