注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

BCB-DG's Blog

...

 
 
 

日志

 
 

Linux多线程编程  

2013-08-03 09:26:59|  分类: Linux |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
//轉
一、简单了解多线程

1、Linux系统下的多线程遵循POSIX线程接口,称为pthread。编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a。因此,后面的编译必须在选项中加入 -lpthread选项,否则提示找不到pthread_create()这些函数。

2、pthread_t 是一个线程的标识符,创建线程用pthread_create(),等待线程结束用pthread_join(),一个最简单的程序:

/////// simpleone.c

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

void thread()
{
     int i;
     for (i=0;i<3;i++)
     {
         printf("This is thread %d .\r\n",i);
         sleep(i);
     }
}

int main()
{
     pthread_t id;
     int i,ret;
     ret = pthread_create(&id,NULL,(void *)thread,NULL);
     if (ret != 0)
     {
         printf("Create thread error!\r\n");
         exit(1);
     }
     for (i=0;i<3;i++)
     {
         printf("This is the main thread %d .\r\n",i);
         sleep(i);
     }
     pthread_join(id,NULL);
     return(0);
}

使用gcc -g -lpthread simpleone.c 编译
使用./a.out运行

结果:
This is thread 0 .
This is thread 1 .
This is the main thread 0 .
This is the main thread 1 .
This is thread 2 .
This is the main thread 2 .

不同的机器运行结果有可能不同,是由于两个“并行”的线程抢夺处理器资源造成的。

线程属性:是否绑定、是否分离、堆栈地址、堆栈大小、优先级
默认的属性:非绑定、非分离、缺省1M的堆栈、与父进程同样级别的优先级。


二、绑定轻进程

关于线程的绑定,牵涉到另外一个概念:轻进程(LWP:Light Weight Process)。轻进程可以理解为内核线程,它位于用户层和系统层之间。系统对线程资源的分配、对线程的控制是通过轻进程来实现的,一个轻进程可以控制一个或多个线程。默认状况下,启动多少轻进程、哪些轻进程来控制哪些线程是由系统来控制的,这种状况即称为非绑定的。绑定状况下,则顾名思义,即某个线程固定的"绑"在一个轻进程之上。被绑定的线程具有较高的响应速度,这是因为CPU时间片的调度是面向轻进程的,绑定的线程可以保证在需要的时候它总有一个轻进程可用。通过设置被绑定的轻进程的优先级和调度级可以使得绑定的线程满足诸如实时反应之类的要求。

#include <pthread.h>

pthread_attr_t attr;
pthread_t tid;

/*初始化属性值,均设为默认值*/
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);

/*PTHREAD_SCOPE_SYSTEM(绑定的) PTHREAD_SCOPE_PROCESS(非绑定的)*/
pthread_create(&tid, &attr, (void *) my_function, NULL);


三、设置分离状态

线程的分离状态决定一个线程以什么样的方式来终止自己。线程的默认属性下,即为非分离状态,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。而分离线程不是这样子的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。程序员应该根据自己的需要,选择适当的分离状态。设置线程分离状态的函数为pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)。第二个参数可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程)。这里要注意的一点是,如果设置一个线程为分离线程,而这个线程运行又非常快,它很可能在pthread_create函数返回之前就终止了,它终止以后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用pthread_cond_timewait函数,让这个线程等待一会儿,留出足够的时间让函数pthread_create返回。设置一段等待时间,是在多线程编程里常用的方法。但是注意不要使用诸如wait()之类的函数,它们是使整个进程睡眠,并不能解决线程同步的问题。


四、设置优先级

另外一个可能常用的属性是线程的优先级,它存放在结构sched_param中。用函数pthread_attr_getschedparam和函数pthread_attr_setschedparam进行存放,一般说来,我们总是先取优先级,对取得的值修改后再存放回去。下面即是一段简单的例子。

#include <pthread.h>
#include <sched.h>

pthread_attr_t attr;
pthread_t tid;
sched_param param;
int newprio=20;

pthread_attr_init(&attr);
pthread_attr_getschedparam(&attr, &param);
param.sched_priority=newprio;
pthread_attr_setschedparam(&attr, &param);
pthread_create(&tid, &attr, (void *)myfunction, myarg);


五、互斥锁对象 Mutex

Mutex是一个互斥锁对象,互斥锁是为了防止多线程同时修改某一公共资源,下面的程序里把它“锁”在了一个叫buffer[10]的缓冲区上,模型是2个Reader和2个Writer,Reader要等到叫buffer的书架上有书的时候才可以read,而Writer也必须在书架没有放满的情况下才可以把新写的书放到书架上。看程序:

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

void reader_function(void);
void writer_function(void);

char buffer[10]={0};
int buffer_has_item=0;
pthread_mutex_t mutex;

int main(void)
{
     pthread_t reader;
     /* 用默认属性初始化一个互斥锁对象*/
     pthread_mutex_init (&mutex,NULL);
     pthread_create(&reader,NULL, (void *)reader_function, NULL);
     writer_function();
}

void writer_function(void)
{
     int i,ti;

     for(i=1;i<3;)
     {
         ti=i;
         /* 锁定互斥锁*/
         pthread_mutex_lock(&mutex);
         printf("Writer %d Locked Buffer.\r\n",i);
         if (buffer_has_item==0)
         {
             buffer_has_item=1;
             strcpy(buffer,"Full");
             printf("++Writer %d fill the buffer with context \"%s\".\r\n",i,buffer);
             i++;
         }
         /* 打开互斥锁*/
         printf("Writer %d Unlocked Buffer.\r\n\n\n",ti);
         pthread_mutex_unlock(&mutex);
         sleep(1);
     }
}

void reader_function(void)
{
     int i,ti;
     for(i=1;i<3;)
     {
         ti=i;
         pthread_mutex_lock(&mutex);
         printf("Reader %d Locked Buffer.\r\n",i);
         if(buffer_has_item==1)
         {
             buffer_has_item=0;
             strcpy(buffer,"Empty");
             printf("--Reader %d clean the buffer with context \"%s\".\r\n",i,buffer);
             i++;
         }
         printf("Reader %d Unlocked Buffer.\r\n\n\n",ti);
         pthread_mutex_unlock(&mutex);
         sleep(1);
     }
}

编译:gcc -o mutex -lpthread -g mutex.c
运行:./mutex

结果:
Reader 1 Locked Buffer.
Reader 1 Unlocked Buffer.

Writer 1 Locked Buffer.
++Writer 1 fill the buffer with context "Full".
Writer 1 Unlocked Buffer.

Writer 2 Locked Buffer.
Writer 2 Unlocked Buffer.

Reader 1 Locked Buffer.
--Reader 1 clean the buffer with context "Empty".
Reader 1 Unlocked Buffer.

Writer 2 Locked Buffer.
++Writer 2 fill the buffer with context "Full".
Writer 2 Unlocked Buffer.

Reader 2 Locked Buffer.
--Reader 2 clean the buffer with context "Empty".
Reader 2 Unlocked Buffer.

注意,sleep()是为了防止一个线程始终占用资源,很多教程使用的是pthread_delay_np(&delay),不过这个似乎只能在solaris系统上用,linux还是用sleep()和usleep()好。
  评论这张
 
阅读(559)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017