多线程编程
一、线程理论基础
线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者。传统的Unix也支持线程的概念,但是在一个进程(process)中只允许有一个线程,这样多线程就意味着多进程。现在,多线程技术已经被许多操作系统所支持,包括Windows/NT,当然,也包括Linux。
1、为什么有了进程的概念后,还要再引入线程呢?使用多线程到底有哪些好处?什么的系统应该选用多线程?我们首先必须回答这些问题。
使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。我们知道,在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的30倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。
使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。
2、多线程程序作为一种多任务、并发的工作方式,还有以下的优点:
(1) 提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况。
(2)使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
(3)改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。
3、Linux系统下的多线程遵循POSIX线程接口,称为pthread。编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a。
注:一个线程所包含的信息呈现出了它在一个进程中的执行环境,它们包括线程ID,线程栈,时刻优先级和策略(a scheduling priority and policy),信号屏蔽字,error变量以及线程相关的特定数据(线程私有数据)。在一个进程中几乎所有的东西都是可以共享的,包括代码段,全局变量以及堆、栈,还包括文件描述符等。一个线程的线程ID是用于在进程中唯一确定的标识,和进程ID不同,它只有在该线程所在的进程中才有意义。
二、多线程程序设计
1、创建线程
1 #include <pthread.h> 2 int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void), void *restrict arg);
参数:tidp指线程id;attr是线程属性,默认时可赋值为空;start_rtn是一个函数指针,线程创建成功后,该函数将作为线程的入口函数开始运行;arg是传递给该线程函数start_rtn的参数。
返回值:创建成功,返回0,并将新创建线程的标识符存放在由tidp指向的地址;若失败,则返回一个非负值。
注:因为pthread的库不是Linux系统的库,所以在进行编译的时候要加上 -lpthread.
1 #include <stdio.h> 2 #include <pthread.h> 3 4 void *myThread1(void) 5 { 6 int i; 7 for (i=0; i<100; i++) 8 { 9 printf("This is the 1st pthread,created by zieckey.\n"); 10 sleep(1);//Let this thread to sleep 1 second,and then continue to run 11 } 12 } 13 14 void *myThread2(void) 15 { 16 int i; 17 for (i=0; i<100; i++) 18 { 19 printf("This is the 2st pthread,created by zieckey.\n"); 20 sleep(1); 21 } 22 } 23 24 int main() 25 { 26 int i=0, ret=0; 27 pthread_t id1,id2; 28 29 /*创建线程1*/ 30 ret = pthread_create(&id1, NULL, (void*)myThread1, NULL); 31 if (ret) 32 { 33 printf("Create pthread error!\n"); 34 return 1; 35 } 36 37 /*创建线程2*/ 38 ret = pthread_create(&id2, NULL, (void*)myThread2, NULL); 39 if (ret) 40 { 41 printf("Create pthread error!\n"); 42 return 1; 43 } 44 45 pthread_join(id1, NULL); 46 pthread_join(id2, NULL); 47 48 return 0; 49 }
编译:gcc thread_create.c -lpthread -o thread_create
传递整型:
1 #include <stdio.h> 2 #include <pthread.h> 3 #include <unistd.h> 4 5 void *create(void *arg) 6 { 7 int *num; 8 num=(int *)arg; 9 printf("create parameter is %d \n",*num); 10 return (void *)0; 11 } 12 int main(int argc ,char *argv[]) 13 { 14 pthread_t tidp; 15 int error; 16 17 int test=4; 18 int *attr=&test; 19 20 error=pthread_create(&tidp,NULL,create,(void *)attr); 21 22 if(error) 23 { 24 printf("pthread_create is not created ... \n"); 25 return -1; 26 } 27 sleep(1); 28 printf("pthread_create is created ...\n"); 29 return 0; 30 }
传递字符串:
1 #include <pthread.h> 2 #include <stdio.h> 3 #include <unistd.h> 4 5 void *create(void *arg) 6 { 7 char *name; 8 name=(char *)arg; 9 printf("The parameter passed from main function is %s \n",name); 10 return (void *)0; 11 } 12 13 int main(int argc, char *argv[]) 14 { 15 char *a="zieckey"; 16 int error; 17 pthread_t tidp; 18 19 error=pthread_create(&tidp, NULL, create, (void *)a); 20 21 if(error!=0) 22 { 23 printf("pthread is not created.\n"); 24 return -1; 25 } 26 sleep(1); 27 printf("pthread is created... \n"); 28 return 0; 29 }
传递结构:
1 #include <stdio.h> 2 #include <pthread.h> 3 #include <unistd.h> 4 #include <stdlib.h> 5 6 struct menber 7 { 8 int a; 9 char *s; 10 }; 11 12 void *create(void *arg) 13 { 14 struct menber *temp; 15 temp=(struct menber *)arg; 16 printf("menber->a = %d \n",temp->a); 17 printf("menber->s = %s \n",temp->s); 18 return (void *)0; 19 } 20 21 int main(int argc,char *argv[]) 22 { 23 pthread_t tidp; 24 int error; 25 struct menber *b; 26 b=(struct menber *)malloc( sizeof(struct menber) ); 27 b->a = 4; 28 b->s = "zieckey"; 29 30 error = pthread_create(&tidp, NULL, create, (void *)b); 31 32 if( error ) 33 { 34 printf("phread is not created...\n"); 35 return -1; 36 } 37 sleep(1); 38 printf("pthread is created...\n"); 39 return 0; 40 }
共享数据:
1 #include <stdio.h> 2 #include <pthread.h> 3 #include <unistd.h> 4 5 //static int a=4; 6 7 int a = 1; 8 9 void *create(void *arg) 10 { 11 printf("new pthread ... \n"); 12 printf("a=%d \n",a); 13 return (void *)0; 14 } 15 16 int main(int argc,char *argv[]) 17 { 18 pthread_t tidp; 19 int error; 20 21 int a=5; 22 23 printf("a = %d\n",a); 24 25 //error=pthread_create(&tidp, NULL, create, NULL); 26 27 if(error!=0) 28 { 29 printf("new thread is not create ... \n"); 30 return -1; 31 } 32 33 sleep(1); 34 35 printf("new thread is created ... \n"); 36 return 0; 37 }
2、终止线程
如果进程中任何一个线程中调用exit或_exit,那么整个进程都会终止。线程正常终止的三种方式如下:
(1) 线程从线程入口函数处返回,其返回值将是该线程的终止状态。
(2)该线程被相同进程中的其他线程所取消。
(3)线程调用pthread_exit函数终止当前线程,该函数的参数将被作为终止状态。
1 #include <pthread.h> 2 void pthread_exit(void *rval_ptr);
功能:终止调用线程。
参数:rval_ptr 是线程退出返回值的指针。
1 #include <stdio.h> 2 #include <pthread.h> 3 #include <unistd.h> 4 5 void *create(void *arg) 6 { 7 printf("new thread is created ... \n"); 8 return (void *)8; 9 //pthread_exit((void *)8); 10 //eixt(0); 11 } 12 13 int main(int argc,char *argv[]) 14 { 15 pthread_t tid; 16 int error; 17 void *temp; 18 19 error = pthread_create(&tid, NULL, create, NULL); 20 printf("main thread!\n"); 21 22 if(error) 23 { 24 printf("thread is not created ... \n"); 25 return -1; 26 } 27 error = pthread_join(tid, &temp); 28 29 if(error) 30 { 31 printf("thread is not exit ... \n"); 32 return -2; 33 } 34 35 printf("thread is exit code %d \n", (int )temp); 36 return 0; 37 }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。