本章主要讲解学习Linux中的线程
注:在Linux系统下的CPU眼中,看到的PCB(task_struct)都要比传统的进程更加轻量化
进程是一个大的整体,包括task_struct(PCB),进程地址空间、文件、信号等,是承担分配系统资源的基本实体,而之前所受的进程都只有一个task_struct,也就是该进程内部只有一个执行流
pid_t vfork(void);
示例:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
int val=100;
pid_t id=vfork();
if(id==0)
{
//child
int cnt=0;
while(1)
{
printf("i am child pid:%d ppid:%d val:%d &val:%p\n",getpid(),getppid(),val,&val);
cnt++;
sleep(1);
if(cnt==2)
val=200;
if(cnt==5)
exit(0);
}
}
else if(id>0)
{
//father
int cnt=0;
while(1)
{
printf("i am father pid:%d ppid:%d val:%d &val:%p\n",getpid(),getppid(),val,&val);
cnt++;
sleep(1);
if(cnt==3)
val=300;
}
}
return 0;
}
注:vfork() 保证子进程先运行,在它调用 exec(进程替换) 或 exit(退出进程)之后父进程才可能被调度运行;如果子进程没有调用 exec, exit, 程序则会导致死锁,程序是有问题的程序,没有意义
注:进程的多个线程共享同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
mypthread.c:
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>
int val=0;
void* Routine(void* avgs)
{
while(1)
{
printf("I am %s... val:%d\n",(char*)avgs,val);
sleep(1);
}
}
int main()
{
pthread_t tid1,tid2,tid3;
int ret1=pthread_create(&tid1,NULL,Routine,(void*)"pthread 1");
if(ret1!=0)
{
fprintf(stderr,"pthread_creat:%s\n",strerror(ret1));
exit(1);
}
int ret2=pthread_create(&tid2,NULL,Routine,(void*)"pthread 2");
if(ret2!=0)
{
fprintf(stderr,"pthread_creat:%s\n",strerror(ret2));
exit(1);
}
int ret3=pthread_create(&tid3,NULL,Routine,(void*)"pthread 3");
if(ret3!=0)
{
fprintf(stderr,"pthread_creat:%s\n",strerror(ret3));
exit(1);
}
while(1)
{
printf("I am main pthread...val:%d\n",val++);
sleep(1);
}
return 0;
}
Makefile:
mypthread:mypthread.c
gcc -o $@ $^ -pthread
.PHONY:clean
clean:
rm -f mypthread
-L
,看到的就是一个个的进程;带-L
就可以查看到每个进程内的多个轻量级进程
pthread_t pthread_self(void);
功能:获得线程自身的ID 注:对于Linux目前实现的NPTL实现而言,pthread_t类型的线程ID,本质就是一个进程地址空间上的一个地址
注:主线程并不使用动态库里的线程栈,而是使用进程里的栈
注:在主线程使用return,以及在线程中使用exit都会终止整个进程
void pthread_exit(void *value_ptr);
注:pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了
int pthread_cancel(pthread_t thread);
注:pthread_cancel函数具有一定的延时性,并不会立即被处理,不建议当线程立即被创建后立即进行cancel取消(线程创建,并不会立即被调度);也不建议在线程退出前执行线程cancel取消(线程可能在取消之前就已经退出了);建议在线程执行中进行cancel取消线程
示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void *thread1(void *arg)
{
printf("%s returning ... \n",(char*)arg);
int *p = (int*)malloc(sizeof(int));
*p = 1;
return (void*)p;
}
void *thread2(void *arg)
{
printf("%s exiting ...\n",(char*)arg);
int *p = (int*)malloc(sizeof(int));
*p = 2;
pthread_exit((void*)p);
}
void *thread3(void *arg)
{
while ( 1 ){ //
printf("%s is running ...\n",(char*)arg);
sleep(1);
}
return NULL;
}
int main( void )
{
pthread_t tid;
void *ret;
// thread 1 return
pthread_create(&tid, NULL, thread1, (void*)"thread 1");
pthread_join(tid, &ret);
printf("thread 1 return, thread id %X, return code:%d\n", tid, *(int*)ret);
free(ret);
// thread 2 exit
pthread_create(&tid, NULL, thread2, (void*)"thread 2");
pthread_join(tid, &ret);
printf("thread 2 exit, thread id %X, return code:%d\n", tid, *(int*)ret);
free(ret);
// thread 3 cancel by other
pthread_create(&tid, NULL, thread3, (void*)"thread 3");
sleep(3);
pthread_cancel(tid);
pthread_join(tid, &ret);
if (ret == PTHREAD_CANCELED)
printf("thread 3 cancel, thread id %X, return code: PTHREAD_CANCELED->%d\n", tid,ret);
else
printf("thread return, thread id %X, return code:%d\n", tid,ret);
return 0;
}
int pthread_join(pthread_t thread, void **value_ptr);
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>
int val=0;
struct Ret
{
int exitno;
int exittime;
//...
};
void* Routine(void* avgs)
{
int cnt=1;
while(1)
{
printf("I am %s... val:%d\n",(char*)avgs,val);
sleep(1);
cnt++;
if(cnt==3)
{
struct Ret* p=(struct Ret*)malloc(sizeof(struct Ret));
p->exitno=0;
p->exittime=6666;
pthread_exit((void*)p);
//pthread_cancel(pthread_self());
}
}
}
int main()
{
pthread_t tid1,tid2,tid3;
pthread_create(&tid1,NULL,Routine,(void*)"pthread 1");
pthread_create(&tid2,NULL,Routine,(void*)"pthread 2");
pthread_create(&tid3,NULL,Routine,(void*)"pthread 3");
int cnt=0;
while(1)
{
printf("I am main pthread...val:%d\n",val++);
sleep(1);
cnt++;
if(cnt==3)
break;
}
printf("wait for pthread...\n");
void* ret;
pthread_join(tid1,&ret);
printf("pthread id:%x exitno:%d exittime:%d\n",tid1,((struct Ret*)ret)->exitno,((struct Ret*)ret)->exittime);
pthread_join(tid2,&ret);
printf("pthread id:%x exitno:%d exittime:%d\n",tid2,((struct Ret*)ret)->exitno,((struct Ret*)ret)->exittime);
pthread_join(tid3,&ret);
printf("pthread id:%x exitno:%d exittime:%d\n",tid3,((struct Ret*)ret)->exitno,((struct Ret*)ret)->exittime);
return 0;
}
int pthread_detach(pthread_t thread);
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void* Routine (void* arg)
{
pthread_detach(pthread_self());
printf("%s detach success!\n");
int cnt=0;
while(cnt<5)
{
cnt++;
printf("%s running...\n",(char*)arg);
sleep(1);
}
printf("%s return...\n");
return NULL;
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,Routine,(void*)"thread");
sleep(2);//等待线程分离
void* ret;
if(pthread_join(tid,&ret)==0)
printf("thread join success! ret:%d\n",(int*)ret);
else
printf("thread join fail... ret:%d\n",(int*)ret);
return 0;
}