Linux下多线程编程


2008-08-23 17:55:08|  分类: linux学习|举报|字号 订阅

       线程(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 <stdio.h>
#include <pthread.h>

void *myThread1(void)
{
    int i;
    for (i=0; i<100; i++)
    {
        printf("This is the 1st pthread,created by zieckey.\n");
        sleep(1);//Let this thread to sleep 1 second,and then continue to run
    }
}

void *myThread2(void)
{
    int i;
    for (i=0; i<100; i++)
    {
        printf("This is the 2st pthread,created by zieckey.\n");
        sleep(1);
    }
}

int main()
{
    int i=0, ret=0;
    pthread_t id1,id2;
    
    ret = pthread_create(&id2, NULL, (void*)myThread1, NULL);
    if (ret)
    {
        printf("Create pthread error!\n");
        return 1;
    }
    
    ret = pthread_create(&id2, NULL, (void*)myThread2, NULL);
    if (ret)
    {
        printf("Create pthread error!\n");
        return 1;
    }
    
    pthread_join(id1, NULL);
    pthread_join(id2, NULL);
    
    return 0;
}


  我们编译此程序:
# gcc pthread_create.c -lpthread

因为pthread的库不是linux系统的库,所以在进行编译的时候要加上-lpthread,否则编译不过,会出现下面错误
thread_test.c: 在函数 ‘create’ 中:
thread_test.c:7: 警告: 在有返回值的函数中,程序流程到达函数尾
/tmp/ccOBJmuD.o: In function `main':thread_test.c:(.text+0x4f):对‘pthread_create’未定义的引用
collect2: ld 返回 1

  运行,我们得到如下结果:
# ./a.out 
This is the 1st pthread,created by zieckey.
This is the 2st pthread,created by zieckey.
This is the 1st pthread,created by zieckey.
This is the 2st pthread,created by zieckey.
This is the 2st pthread,created by zieckey.
This is the 1st pthread,created by zieckey.
....

两个线程交替执行。
此例子介绍了创建线程的方法。
下面例子介绍向线程传递参数。


例程2:
    功能:向新的线程传递整形值
    程序名称:pthread_int.c
/********************************************************************************************
**    Name:pthread_int.c
**    Used to study the multithread programming in Linux OS
**    Pass a parameter to the thread.
**    Author:zeickey
**    Date:2006/9/16        
**    Copyright (c) 2006,All Rights Reserved!
*********************************************************************************************/

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

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  
虽说个人对多线程编程已很熟悉了,但是做一些备份的东西总归没有错;继续鄙视我吧,到处转载,到处剽窃。
                
                
                

本文来自ChinaUnix博客,假如查看原文请点:http://blog.chinaunix.net/u1/54524/showart_445680.html 

以上内容由 华夏名网 收集整理,如转载请注明原文出处,并保留这一部分内容。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值