免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2268 | 回复: 0
打印 上一主题 下一主题

linux多线程机制线程同步 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-02-04 23:30 |只看该作者 |倒序浏览
1.引言
  目前,许多流行的多任务操作系统都提供线程机制,线程就是程序中的
单个顺序控制流。利用多线程进行程序设计,就是将一个程序(进程)的任务划分为执行的多个部分(线程)
,每一个线程为一个顺序的单控制流,而所有线程都是并发执行的,这样,多线程程序就可以实现并行计算,高效利用多处理器。线程可分为用户级线程和内核级线
程两种基本类型。用户级线程不需要内核支持,可以在用户程序中实现,线程调度、同步与互斥都需要用户程序自己完成。内核级线程需要内核参与,由内核完成线
程调度并提供相应的系统调用,用户程序可以通过这些接口函数对线程进行一定的控制和管理。Linux操作系统提供了LinuxThreads库,它是符合
POSIX1003.1c标准的内核级多线程函数库。在linuxthreads库中提供了一些多线程编程的关键函数,在多线程编程时应包括
pthread.h文件。
  2.LinuxThread中的关键库函数
  2.1线程的创建和终止
  int pthread_create(pthread_t * pthread,const pthread_attr_t
*attr,void *(*start_routine(*void)),void
*arg);调用此函数可以创建一个新的线程,新线程创建后执行start_routine
指定的程序。其中参数attr是用户希望创建线程的属性,当为NULL时表示以默认的属性创建线程。arg是向start_routine
传递的参数。当成功创建一个新的线程时,系统会自动为新线程分配一个线程ID号,并通过pthread 返回给调用者。
  void pthread_exit(void *value_ptr);调用该函数可以退出线程,参数value_ptr是一个指向返回状态值的指针。
  2.2线程控制函数
  pthread_self(void);为了区分线程,在线程创建时系统为其分配一个唯一的ID号,由pthread_create()返回给调用者,也可以通过pthread_self()获取自己的线程ID。
  Int pthread_join (pthread- t thread , void * *status);这个函数的作用是等待一个线程的结束。调用pthread_join()的线程将被挂起直到线程ID为参数thread 指定的线程终止。
  int pthread_detach(pthread_t pthread);参数pthread代表的线程一旦终止,立即释放调该线程占有的所有资源。
  2.3线程间的互斥
  互斥量和临界区类似,只有拥有互斥量的线程才具有访问资源的权限,
由于互斥对象只有一个,这就决定了任何情况下共享资源(代码或变量)都不会被多个线程同时访问。使用互斥不仅能够在同一应用程序的不同线程中实现资源的安
全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享。Linux中通过pthread_mutex_t来定义互斥体机制完成互斥操作。具体的
操作函数如下
  pthread_mutex_init(pthread_mutex_t *mutex,const
pthread_mutexattr_t
*attr);初使化一个互斥体变量mutex,参数attr表示按照attr属性创建互斥体变量mutex,如果参数attr为NULL,则以默认的方
式创建。
  pthread_mutex_lock(pthread_mutex_t *mutex);给一个互斥体变量上锁,如果mutex指定的互斥体已经被锁住,则调用线程将被阻塞直到拥有mutex的线程对mutex解锁为止。
  Pthread_mutex_unlock(pthread_mutex_t *mutex);对参数mutex指定的互斥体变量解锁。
  2.4线程间的同步
  同步就是线程等待某一个事件的发生,当等待的事件发生时,被等待的线程和事件一起继续执行。如果等待的事件未到达则挂起。在linux操作系统中是通过条件变量来实现同步的。
  Pthread_cond_init(pthread_cond_t *cond,const pthread_cond_t *attr);这个函数按参数attr指定的属性初使化一个条件变量cond。
  Pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);等待一个事件(条件变量)的发生,发出调用的线程自动阻塞,直到相应的条件变量被置1。等待状态的线程不占用CPU时间。
  pthread_cond_signal(pthread_cond_t *cond);解除一个等待参数cond指定的条件变量的线程的阻塞状态。


  3.多线程编程的应用实例
  在这里利用多线程技术实现生产者和消费者问题,生产者线程向一缓冲区中写数据,
消费者线程从缓冲区中读取数据,由于生产者线程和消费者线程共享同一缓冲区,为了正确读写数据,在使用缓冲队列时必须保持互斥。生产者线程和消费者线程必
须满足:生产者写入缓冲区的数目不能超过缓冲区容量,消费者读取的数目不能超过生产者写入的数目。在程序中使用了一个小技巧来判断缓冲区是空还是满。在初
始化时读指针和写指针为0;如果读指针等于写指针,则缓冲区是空的;如果(写指针+ 1) % N
等于读指针,则缓冲区是满的,%表示取余数,这时实际上有一个单元空出未用。下面是完整的程序段和注释。
  #include
  #include
  #define BUFFER_SIZE 8
  struct prodcons {
  int buffer[BUFFER_SIZE];
  pthread_mutex_t lock;      //互斥LOCK
  int readpos , writepos;
  pthread_cond_t notempty;   //缓冲区非空条件判断
  pthread_cond_t notfull;    //缓冲区未满条件判断
  };
  void init(struct prodcons * b){
  pthread_mutex_init(&b->lock,NULL);
  pthread_cond_init(&b->notempty,NULL);
  pthread_cond_init(&b->notfull,NULL);
  b->readpos=0;
  b->writepos=0;
  }
  void put(struct prodcons* b,int data){
  pthread-_mutex_lock(&b->lock);
  if((b->writepos + 1) % BUFFER_SIZE == b->readpos)
  {
  pthread_cond_wait(&b->notfull, &b->lock) ;
  }
  b->buffer[b->writepos]=data;
  b->writepos++;
  if(b->writepos >= BUFFER_SIZE)
  b->writepos=0;
  pthread_cond_signal(&b->notempty);
  pthread_mutex_unlock(&b->lock);
  }
  int get(struct prodcons *b){
  int data;
  pthread_mutex_lock(&b->lock);
  if(b->writepos == b->readpos)
  {
  pthread_cond _wait(&b->notempty, &b->lock);
  }
  data = b->buffer[b->readpos];
  b->readpos++;
  if(b->readpos >= BUFFER_SIZE)
  b->readpos=0;
  pthread_cond_signal(&b->notfull);
  pthread_mutex_unlock(&b->lock);
  return data;
  }

  #define OVER (-1)
  struct prodcons buffer;
  void *producer(void *data)
  {
  int n;
  for(n = 0; n < 10000; n++)
  {
  printf("%d \n", n) ;
  put(&buffer, n);
  }
  put(&buffer, OVER);
  return NULL;
  }
  void *consumer(void * data)
  {
  int d;
  while(1)
  {
  d = get(&buffer);
  if(d == OVER)
  break;
  printf("%d\n", d);
  }
  return NULL;
  }
  int main(void)
  {
  pthread_t th_a, th_b;
  void *retval;
  init(&buffer);
  pthread_create(&th_a, NULL, producer, 0);
  & nbsp;   pthread_create(&th_b, NULL, consumer, 0);
  pthread_join(th_a, &retval);
  pthread_join(th_b, &retval);
  return 0;
  }
  上
面的例子中,生产者负责将1到1000的整数写入缓冲区,而消费者负责从同一个缓冲区中读取写入的整数并打印出来。因为生产者和消费者是两个同时运行的线
程,并且要使用同一个缓冲区进行数据交换,因此必须利用一种机制进行同步。通过上面的例子我们可以看到,多线程的最大好处是,除堆栈之外,几乎所有的数据
均是共享的,因此线程间的通讯效率很高;缺点:因为共享所有数据,从而非常容易导致线程之间互相破坏数据,这一点在编程时必须注意。
  4.结束语
  Linux中基于POSIX标准的很好的支持了多线程技术,它减少了程序并发执行时的系统开销,提高了计算机的工作效率。在具体编程过程中要了
解线程的间的关系,还要考虑共享数据的保护,在互斥和同步机制下保证代码的高效运行,程序编译时用gcc -D –REENTRANT
-libpthread.xx.so filename.c编译。
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/106123/showart_2178143.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP