一.概述:
首先谈一下为什么要有线程。众所周知,一个进程只能进行一个执行流,虽然能创建子进程,但创建,终止,切换进程和进程间的通信的开销比较大,所以现代操作系统一般都使用线程。
现在再谈一下我所了解的线程功能。一般可以这样认为,进程负责的是分配资源,而线程负责的是调度和执行。线程又叫轻量级进程。而传统的进程即负责分配资源,又承担一个线程的执行。
进程和线程的区别:除了上面功能与性能的不同,还可以从进程管理的角度来区别。在单线程模型中,进程的表示包括它的进程控制块,用户地址空间,以及进程执行中管理调用/返回行为的用户栈,内核栈。在多线程环境中,进程只有一个与之关联的进程控制块和用户地址空间,而线程都有一个独立的栈,还有独立的控制块(包括寄存器,优先级和其它与线程相关的状态信息)。如下图:(摘自操作系统精髓与设计原理第4章)
注:如果在多处理器机器上,多线程的性能会更优。
二.相关函数:(PS:这里的线程库函数是由POSIX标准定义的,称为POSIX thread或者pthread。)
- pthread_create: int pthread_create(pthread_t *pthread, const pthread_attr_t *attr,
void *(*start_toutine)(void *), void *arg)
函数功能:创建一个线程,使线程从传入的函数指针所指的函数中开始执行。
pthread参数:输出型参数,创建成功会把线程id放入里面。
attr参数:用来设置线程的属性,如线程的分离状态属性,线程栈的大小等。一般为NULL就可以了。
start_toutine参数:函数指针,用于指明线程从哪里开始执行。
arg参数:传入函数指针所指的函数的参数。
返回值:所有pthread函数都是成功返回0,失败返回一个错误号。可以用strerror显示错误号。
PS:主线程会从函数返回出继续往下执行。
2.pthread_exit:void pthread_exit(void *retval)
函数功能:线程可以调用自己进行注销操作。
retval参数:退出时返回的值。
3.pthread_cancel:int pthread_cancel(pthread_t pthread)
函数功能:注销线程id为pthread的线程。
返回值:成功返回0,失败返回一个错误号。
4.pthread_join:int pthread_join(pthread_t pthread, void** retval)
函数功能:将线程id为pthread的线程挂起等待,直到线程终止,终止状态保持到retval中。
retval参数:输出型参数,用于保存线程终止的终止状态。不同的终止方法有不同的终止状态:
(1).如果线程通过return返回,retval中指向的单元里存放的是线程函数的返回值。
(2).如果线程被别的线程调用pthread_cancel异常终止,retval指向的单元中存放的是常数PTHREAD_CALCELED。
(3).如果线程自己调用pthread_exit()函数终止的,retval指向的单元中存放的是传给pthead_exit()的参数。
返回值:成功返回0,失败返回一个错误号。
三.相关代码:(PS:编译时要加 -Lpthread)
- 创建一个进程:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<pthread.h> 4 5 pthread_t tid; 6 7 void* create_thread(void *ptr) 8 { 9 printf("%s . pid is:%d tid is:%ul \n",(char *)ptr, (int)getpid(), (unsigned long long)pthread_self()); 10 return NULL; 11 } 12 13 int main() 14 { 15 int err = pthread_create(&tid, NULL, create_thread, "i‘m a thread"); 16 if(err != 0) 17 { 18 printf("create thread failed! info is :%s", strerror(err)); 19 exit(err); 20 } 21 22 printf("main thread run. pid is:%d tid is:%ul \n", (int)getpid(), (unsigned long long)pthread_self());//linux 下tid为一个地址值 23 sleep(1); 24 return 0; 25 }
执行结果:
2.线程等待:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<pthread.h> 4 5 void *create_thread1(void *ptr) 6 { 7 printf("this is thread1\n"); 8 return (void *)1; 9 } 10 11 void *create_thread2(void *ptr) 12 { 13 printf("this is thread2\n"); 14 pthread_exit((void *)2); 15 } 16 17 void *create_thread3(void *ptr) 18 { 19 while(1) 20 { 21 printf("this is thread3,waiting for be calceled.....\n"); 22 sleep(1); 23 } 24 return NULL; 25 } 26 27 int main() 28 { 29 pthread_t tid; 30 void* ret; 31 32 int err1 = pthread_create(&tid, NULL, create_thread1, NULL); 33 if(err1 != 0) 34 { 35 printf("create thread failed!"); 36 } 37 pthread_join(tid, &ret); 38 printf("thread is returned,tid is:%ul return code is:%d \n", (unsigned long long)pthread_self(), (int)ret); 39 40 int err2 = pthread_create(&tid, NULL, create_thread2, NULL); 41 if(err2 != 0) 42 { 43 printf("create thread failed!"); 44 } 45 pthread_join(tid, &ret); 46 printf("thread is exited,tid is:%ul return code is:%d \n", (unsigned long long)pthread_self(), (int)ret); 47 48 int err3 = pthread_create(&tid, NULL, create_thread3, NULL); 49 if(err3 != 0) 50 { 51 printf("create thread failed!"); 52 } 53 sleep(3); 54 pthread_cancel(tid); 55 pthread_join(tid, &ret); 56 printf("thread is canceled,tid is:%ul return code is:%d \n", (unsigned long long)pthread_self(), (int)ret); 57 58 return 0; 59 }
执行结果: