线程机制:并发函数的使用

一、背景

    之前学习过进程的概念,而计算机是不可能只单单运行一个进程的。我们使用fork与exec等系统调用来使进程并发执行。然而对于一个进程而言,该进程一定是有多个函数的,那么这些函数是否可以并发执行呢?当然是可以的,这一机制就叫做线程机制。

二、一个单线程程序

#include<unistd.h>
#include<stdio.h>
#define NUM 5

int main()
{
  void print_msg(char *);

  print_msg("Hello");
  print_msg("World\n");
}

void print_msg(char *m)
{
  int i;
  for(i=0;i<NUM;i++){
    printf("%s",m);
    fflush(stdout);
    sleep(1);
  }
}

这是一个十分简单的单线程程序,执行结果:


可以看到程序先执行完五个hello的输出,接着执行五个world的输出。

现在我们考虑的是如何输出形如hello world\n  hello world\n ... 这样的结果。

这就需要函数并发的执行。

三、简单的多线程程序

这里使用了两个系统调用:pthread_create , pthread_join。

一个用来创建新的线程,后一个用来等待某线程的终止。具体使用可使用man命令查看。

该源程序如下:

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>

#define NUM 5

int main()
{
  pthread_t t1,t2;
  void *thread(void *);

  pthread_create(&t1,NULL,thread,(void *)"Hello");
  pthread_create(&t2,NULL,thread,(void *)"World\n");
  pthread_join(t1,NULL);
  pthread_join(t2,NULL);
}

void *thread(void *m)
{
  int i;

  for(i=0;i<NUM;i++){
    printf("%s",m);
    sleep(1);
    }
  return NULL;
}

该程序执行结果如下:


或许大家会有疑问,为什么前半部分输出的helloworld很正常,到后半部分就乱了呢。

原因是thread函数是并发执行的,也可理解为函数在同时运行,所以输出hello与输出world的先后顺序并不是一定的,

每一次的输出结果都有可能相同也有可能不相同。

四、共享全局变量

    对比进程来学习线程,进程之间有进程之间的通信方式,进程可通过管道、socket、信号、退出/等待来进行进程间的通信。

而线程之间通过什么通信方式来进行它们之间的分工合作呢?

    我们明白,各个线程虽不相同,但都是同在同一个进程中运行的,也就是说,它们之间是共享全局变量的。通过全局变量的使用就可以完成线程之间的通信。

    线程之间可通过全局变量进行合作。这里举一个例子:

#include<unistd.h>
#include<stdio.h>
#include<pthread.h>

#define NUM 5

int counter = 0;

int main()
{
  pthread_t t1;
  void *print_count(void *);
  int i;

  pthread_create(&t1,NULL,print_count,NULL);
  for(i=0;i<NUM;i++){
    counter++;
    sleep(1);
  }
  pthread_join(t1,NULL);
}

void *print_count(void *m)
{
  int i;
  for(i=0;i<NUM;i++){
    printf("count = %d\n",counter);
    sleep(1);
  }
  return NULL;
}

该进程有两个线程并发执行,使用同一个全局变量counter,两个线程都有对counter的访问权,都可以对其进行访问。

初始线程每一秒对counter进行加1操作,而新线程每一秒对counter进行一次打印操作。

这样,我们看一下输出结果:


我们可以看到,两次输出有不一样的结果,原因就在于在新线程对全局变量counter进行打印时,可能初始线程刚刚对counter进行了加1操作,

也可能是刚打印完初始线程才对counter进行了加1操作。这就造成了输出结果的不确定。

由此我们可以看到,使用全局变量既可进行通信,也同时是一个危险的行为。

五、总结

    本文简单介绍了并发函数的使用,其中涉及了几个简单的系统调用。需要注意的是,并发函数使用全局变量既方便,但也危险。本文还未涉及如何安全的对全局变量进行访问。待到下次分析。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值