c中的多线程详解

来源:互联网 发布:天庭淘宝店txt 编辑:程序博客网 时间:2024/06/05 15:13

什么是线程?

线程是进程里面的一个单独的序列流,因为线程包含一些进程的属性,所以线程也叫轻量级进程。

进程和线程有什么区别?

线程不是独立于其他类似进程,因此线程与其他线程共享其代码部分,数据部分和操作系统资源,如打开的文件和信号。但是像进程一样,线程也有自己的计数器(pc),寄存器集和堆栈空间。

为什么需要多线程?

线程是通过并行性改进应用程序的流行方式,例如在浏览器中多个选项卡可以对应不同线程,MS world使用多个线程,一个线程格式化文本,一个线程格式化输入。
线程的操作速度比进程快:
1.线程创建速度快
2.线程上下文切换快
3.线程可以轻松终止,简单快捷
4.线程之间通信速度快

我们可以在c中编写多线程程序吗?

与Java不同,语言标准不支持多线程。POSIX线程(或Pthreads)是针对线程的POSIX标准。gth编译器可以实现pthread。
来看一个简单的例子:
#include <pthread.h>#include <stdlib.h>#include <unistd.h> void *thread_function(void *arg) {  int i;  for ( i=0; i<20; i++) {    printf("Thread says hi!\n");    sleep(1);  }  return NULL;}int main(void) {  pthread_t mythread;    if ( pthread_create( &mythread, NULL, thread_function, NULL) ) {    printf("error creating thread.");    abort();  }  if ( pthread_join ( mythread, NULL ) ) {    printf("error joining thread.");    abort();  }  exit(0);}
这个程序最终会将
Thread says hi
运行20次以后结束程序

程序编译与运行:

我们详细的来看看这个程序的细节:
上面是一个非常简单的线程的程序,虽然她没有什么实际有用的功能,但他可以帮助我们很好的理解线程的运行机制,下面我们一步步来看这个程序在干什么。mian()中声明了mythread,它的数据类型为pthread_t,这是定义在<pthread.h>中的一种数据类型,这里mythread相当于一个thread id(简称tid),就是线程id的意思,你也可以理解为一个线程句柄。
记住mythread只是一个线程句柄(tid)接下来我们就要用到pthread_creat()来创建一个真正活动的线程。pthread_creat()的返回值是0 OR 1意思是如果线程创建成功则返回0,创建失败返回1.这个函数中有四个参数:
 第一个参数:&mythread 是指向 mythread 的指针。
第二个参数:当前为null,这个参数可以来定义线程的某些属性
第三个参数:当前创建的线程(下面叫做新线程)所要调用的函数,上面程序里是thread_function()这个函数,当该函数返回值时,新线程也终止。
第四个参数:这里是用来传参的,因为上面我们调用的thread_function()这个函数不需要参数,所以第四个参数设置为null。
我们还要清楚一点上面的程序我们实际是创建了两个线程,main()也是一个线程。我们可以这样理解,如果我们不用POSIX创建新线程,则我们以前写的程序都是单线程的。
你可能会想我们现在有了两个线程,但是它们究竟是怎么运行的呢?新线程创建以后主线程继续执行pthread_join()这个函数,当主线程到达这个函数时,由于新线程还没有运行完毕,所以主线程中断(咸党与休眠)等待新线程执行完毕后将新线程合并(你可以理解为释放掉或者清理掉)现在,程序就只有一个线程了。
我们来看一看pthread_join()这个函数的两个参数:第一个参数同样是一个指向mythread得指针,第二个参数和creat的第四个参数相似。当程序退出时,所有新线程已经使用 pthread_join() 合并了。这就是应该如何处理在程序中创建的每个新线程的过程。如果没有合并一个新线程,则它仍然对系统的最大线程数限制不利。这意味着如果未对线程做正确的清理,最终会导致 pthread_create() 调用失败。

下面我们来看一个同步漫游的例子可以帮助你更好的理解:
#include <pthread.h>#include <stdlib.h>#include <unistd.h>#include <stdio.h>int myglobal; void *thread_function(void *arg) {  int i,j;  for ( i=0; i<20; i++) {    //myglobal += 1;    j = myglobal;    j=j+1;    printf(".");    fflush(stdout);    sleep(1);    myglobal=j;  }  return NULL;}int main(void) {  pthread_t mythread;  int i;  if ( pthread_create( &mythread, NULL, thread_function, NULL) ) {    printf("error creating thread.");    abort();  }  for ( i=0; i<20; i++) {    myglobal=myglobal+1;    printf("o");    fflush(stdout);    sleep(1);  }  if ( pthread_join ( mythread, NULL ) ) {    printf("error joining thread.");    abort();  }  printf("\nmyglobal equals %d\n",myglobal);  exit(0);}

编译过程同上(略)
运行结果:

这个程序是双线程的,每个线程都给mythread加了20次1,但是结果为什么不是40呢,是不是有点惊讶,下面我们仔细的分析一下这个程序:
首先我们知道的是对于线程来说不像进程一样有子与父的区别,每一个进程都是平等的,处在同一层次的,对于上面这个程序,在这里两个线程几乎同时进行,产生上述结果差异的根本原因就在于thread_function()这个函数中我们把j的值赋值给myread是在sleep(1)后面,什么意思呢?就是新线程真正实现methread+1是发生在sleep(1)后面,这样当两个程序几乎同时进行时,新线程会将主线程的值覆盖这样就产生了21这个结果,你可以试着把程序中的注释去掉。稍加修改让新线程mythread+1发生在sleep之前,看看结果是什么?





原创粉丝点击