首页 > 代码库 > 多线程编程
多线程编程
一、线程理论基础
线程(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 run11 }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 }
多线程编程