免费注册 查看新帖 |

Chinaunix

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

Linux下多线程编程详解 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-10-25 12:31 |只看该作者 |倒序浏览

线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者。传统的Unix也支持线程的概念,但是在一个进程(process)中只允许有一个线程,这样多线程就意味着多进程。
现在,多线程技术已经被许多操作系统所支持,包括Windows/NT,当然,也包括Linux。
  为什么有了进程的概念后,还要再引入线程呢?使用多线程到底有哪些好处?什么的系统应该选用多线程?我们首先必须回答这些问题。
  使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。我们知道,在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的30倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。
  使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。
  除了以上所说的优点外,不和进程比较,多线程程序作为一种多任务、并发的工作方式,当然有以下的优点:
  1) 提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况。
  2) 使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
  3) 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。
  下面我们先来尝试编写一个简单的多线程程序。
  简单的多线程编程
  Linux系统下的多线程遵循POSIX线程接口,称为pthread。编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a。顺便说一下,Linux下pthread的实现是通过系统调用clone()来实现的。clone()是Linux所特有的系统调用,它的使用方式类似fork,关于clone()的详细情况,有兴趣的读者可以去查看有关文档说明。下面我们展示一个最简单的多线程程序 pthread_create.c。
一个重要的线程创建函数原型:
#include
int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr, void *(*start_rtn)(void),void *restrict arg);
    返回值:若是成功建立线程返回0,否则返回错误的编号
    形式参数:
                pthread_t *restrict tidp 要创建的线程的线程id指针
                const pthread_attr_t *restrict attr 创建线程时的线程属性
                void* (start_rtn)(void) 返回值是void类型的指针函数
                void *restrict arg   start_rtn的行参
               
例程1:                                
    功能:创建一个简单的线程
    程序名称:pthread_create.c         
/********************************************************************************************
**    Name:pthread_create.c
**    Used to study the multithread programming in Linux OS
**    Author:zeickey
**    Date:2006/9/16        
**    Copyright (c) 2006,All Rights Reserved!
*********************************************************************************************/
#include
#include
void *myThread1(void)
{
    int i;
    for (i=0; i
#include
#include
void *create(void *arg)
{
    int *num;
    num=(int *)arg;
    printf("create parameter is %d \n",*num);
    return (void *)0;
}
int main(int argc ,char *argv[])
{
    pthread_t tidp;
    int error;
   
    int test=4;
    int *attr=&test;
   
    error=pthread_create(&tidp,NULL,create,(void *)attr);
    if(error)
        {
        printf("pthread_create is created is not created ... \n");
        return -1;
        }
    sleep(1);
    printf("pthread_create is created ...\n");
    return 0;        
}
    编译方法:
gcc -lpthread pthread_int.c -Wall
    执行结果:
create parameter is 4
pthread_create is created is  created ...
    例程总结:
    可以看出来,我们在main函数中传递的整行指针,传递到我们新建的线程函数中。
    在上面的例子可以看出来我们向新的线程传入了另一个线程的int数据,线程之间还可以传递字符串或是更复杂的数据结构。
例程3:
    程序功能:向新建的线程传递字符串
        程序名称:pthread_string.c
/********************************************************************************************
**    Name:pthread_string.c
**    Used to study the multithread programming in Linux OS
**    Pass a ‘char*‘ parameter to the thread.
**    Author:zeickey
**    Date:2006/9/16        
**    Copyright (c) 2006,All Rights Reserved!
*********************************************************************************************/
#include
#include
#include
void *create(void *arg)
{
    char *name;
    name=(char *)arg;
    printf("The parameter passed from main function is %s  \n",name);
    return (void *)0;
}
int main(int argc, char *argv[])
{
    char *a="zieckey";
    int error;
    pthread_t tidp;
    error=pthread_create(&tidp, NULL, create, (void *)a);
    if(error!=0)
    {
        printf("pthread is not created.\n");
        return -1;
    }
    sleep(1);
    printf("pthread is created... \n");
    return 0;
}   
  编译方法:
gcc -Wall pthread_string.c -lpthread
    执行结果:
The parameter passed from main function is zieckey  
pthread is created...
    例程总结:
    可以看出来main函数中的字符串传入了新建的线程中。
例程4:
    程序功能:向新建的线程传递字符串
        程序名称:pthread_struct.c
/********************************************************************************************
**    Name:pthread_struct.c
**    Used to study the multithread programming in Linux OS
**    Pass a ‘char*‘ parameter to the thread.
**    Author:zeickey
**    Date:2006/9/16        
**    Copyright (c) 2006,All Rights Reserved!
*********************************************************************************************/
#include
#include
#include
#include
struct menber
{
    int a;
    char *s;
};
void *create(void *arg)
{
    struct menber *temp;
    temp=(struct menber *)arg;
    printf("menber->a = %d  \n",temp->a);
    printf("menber->s = %s  \n",temp->s);
    return (void *)0;
}
int main(int argc,char *argv[])
{
    pthread_t tidp;
    int error;
    struct menber *b;
    b=(struct menber *)malloc( sizeof(struct menber) );
    b->a = 4;
    b->s = "zieckey";
    error = pthread_create(&tidp, NULL, create, (void *)b);
    if( error )
    {
        printf("phread is not created...\n");
        return -1;
    }
    sleep(1);
    printf("pthread is created...\n");
    return 0;
}
  编译方法:
gcc -Wall pthread_struct.c -lpthread
    执行结果:
menber->a = 4  
menber->s = zieckey  
pthread is created...
    例程总结:
    可以看出来main函数中的一个结构体传入了新建的线程中。
    线程包含了标识进程内执行环境必须的信息。他集成了进程中的所有信息都是对线程进行共享的,包括文本程序、程序的全局内存和堆内存、栈以及文件描述符。
   
例程5:
    程序目的:验证新建立的线程可以共享进程中的数据
    程序名称:pthread_share.c  
/********************************************************************************************
**    Name:pthread_share_data.c
**    Used to study the multithread programming in Linux OS
**    Pass a ‘char*‘ parameter to the thread.
**    Author:zeickey
**    Date:2006/9/16        
**    Copyright (c) 2006,All Rights Reserved!
*********************************************************************************************/
#include
#include
#include
static int a=4;
void *create(void *arg)
{
    printf("new pthread ... \n");
    printf("a=%d  \n",a);
    return (void *)0;
}
int main(int argc,char *argv[])
{
    pthread_t tidp;
    int error;
   
    a=5;
    error=pthread_create(&tidp, NULL, create, NULL);
    if(error!=0)
    {
        printf("new thread is not create ... \n");
        return -1;
    }
   
    sleep(1);
   
    printf("new thread is created ... \n");
    return 0;
}
   
  编译方法:
gcc -Wall pthread_share_data.c -lpthread
    执行结果:
new pthread ...
a=5  
new thread is created ...
    例程总结:
可以看出来,我们在主线程更改了我们的全局变量a的值的时候,我们新建立的线程则打印出来了改变的值,可以看出可以访问线程所在进程中的数据信息。
         2、线程的终止
    如果进程中任何一个线程中调用exit,_Exit,或者是_exit,那么整个进程就会终止,
    与此类似,如果信号的默认的动作是终止进程,那么,把该信号发送到线程会终止进程。
    线程的正常退出的方式:
       (1) 线程只是从启动例程中返回,返回值是线程中的退出码
       (2) 线程可以被另一个进程进行终止
       (3) 线程自己调用pthread_exit函数
    两个重要的函数原型:
#include
void pthread_exit(void *rval_ptr);
/*rval_ptr 线程退出返回的指针*/
int pthread_join(pthread_t thread,void **rval_ptr);
   /*成功结束进程为0,否则为错误编码*/
    例程6
    程序目的:线程正常退出,接受线程退出的返回码
    程序名称:pthread_exit.c
/********************************************************************************************
**    Name:pthread_exit.c
**    Used to study the multithread programming in Linux OS
**    A example showing a thread to exit and with a return code.
**    Author:zeickey
**    Date:2006/9/16        
**    Copyright (c) 2006,All Rights Reserved!
*********************************************************************************************/
#include
#include
#include
void *create(void *arg)
{
    printf("new thread is created ... \n");
    return (void *)8;
}
int main(int argc,char *argv[])
{
    pthread_t tid;
    int error;
    void *temp;
    error = pthread_create(&tid, NULL, create, NULL);
    if( error )
    {
        printf("thread is not created ... \n");
        return -1;
    }
    error = pthread_join(tid, &temp);
    if( error )
    {
        printf("thread is not exit ... \n");
        return -2;
    }
   
    printf("thread is exit code %d \n", (int )temp);
    return 0;
}
  编译方法:
gcc -Wall pthread_exit.c -lpthread
    执行结果:
new thread is created ...
thread is exit code 8
    例程总结:
可以看出来,线程退出可以返回线程的int数值。线程退出不仅仅可以返回线程的int数值,还可以返回一个复杂的数据结构。
    例程7
    程序目的:线程结束返回一个复杂的数据结构
    程序名称:pthread_return_struct.c
#include
#include
#include
struct menber
{
    int a;
    char *b;
}temp={8,"zieckey"};
void *create(void *arg)
{
    printf("new thread ... \n");
    return (void *)&temp;
}
int main(int argc,char *argv[])
{
    int error;
    pthread_t tid;
    struct menber *c;
    error = pthread_create(&tid, NULL, create, NULL);
   
    if( error )
    {
        printf("new thread is not created ... \n");
        return -1;
    }
    printf("main ... \n");
    error = pthread_join(tid,(void *)&c);
    if( error )
    {
        printf("new thread is not exit ... \n");
        return -2;
    }
    printf("c->a = %d  \n",c->a);
    printf("c->b = %s  \n",c->b);
    sleep(1);
    return 0;
}
  编译方法:
gcc -Wall pthread_return_struct.c -lpthread
    执行结果:
main ...
new thread ...
c->a = 8
c->b = zieckey
例程总结:
一定要记得返回的数据结构要是在这个数据要返回的结构没有释放的时候应用,
如果数据结构已经发生变化,那返回的就不会是我们所需要的,而是脏数据
3、线程标识
    函数原型:
   
#include
pthread_t pthread_self(void);
pid_t getpid(void);
    getpid()用来取得目前进程的进程识别码,函数说明
    例程8
    程序目的:实现在新建立的线程中打印该线程的id和进程id
    程序名称:pthread_id.c
   
/********************************************************************************************
**    Name:pthread_id.c
**    Used to study the multithread programming in Linux OS.
**    Showing how to get the thread's tid and the process's pid.
**    Author:zeickey
**    Date:2006/9/16        
**    Copyright (c) 2006,All Rights Reserved!
*********************************************************************************************/
#include
#include
#include  /*getpid()*/
void *create(void *arg)
{
    printf("New thread .... \n");
    printf("This thread's id is %u  \n", (unsigned int)pthread_self());
    printf("The process pid is %d  \n",getpid());
    return (void *)0;
}
int main(int argc,char *argv[])
{
    pthread_t tid;
    int error;
    printf("Main thread is starting ... \n");
    error = pthread_create(&tid, NULL, create, NULL);
    if(error)
    {
        printf("thread is not created ... \n");
        return -1;
    }
    printf("The main process's pid is %d  \n",getpid());
    sleep(1);
    return 0;
}
    编译方法:
   
gcc -Wall -lpthread pthread_id.c
    执行结果:
Main thread is starting ...
The main process's pid is 3307  
New thread ....
This thread's id is 3086347152  
The process pid is 3307  
原文地址
http://www.yuanma.org/data/2007/0921/article_2859.htm

本文转自:
http://blog.chinaunix.net/u/25975/showart_402864.htm



本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/38279/showart_407329.html

论坛徽章:
0
2 [报告]
发表于 2014-06-24 09:40 |只看该作者
对于初学者来说用处非常大,谢谢 LZ的分享。。顶

论坛徽章:
0
3 [报告]
发表于 2014-09-11 17:36 |只看该作者
谢谢楼主的分享。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP