c中的多线程详解 - Go语言中文社区

c中的多线程详解


什么是线程?

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

进程和线程有什么区别?

线程不是独立于其他类似进程,因此线程与其他线程共享其代码部分,数据部分和操作系统资源,如打开的文件和信号。但是像进程一样,线程也有自己的计数器(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 %dn",myglobal);
  exit(0);
}

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

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





版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/lyztyycode/article/details/72811378
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2019-08-27 22:04:22
  • 阅读 ( 1418 )
  • 分类:Linux

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢