Linux C进程与多线程入门—(4)简单多线程程序

一、进程与线程

(1)线程是进程的一个实体,是CPU调度和分派的基本单位,,它是比进程更小的能独立运行的基本单位.


    (2)进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

下图是多线程的结构:

 

而进程之间的通信有两种方式,一种是在两个进程之间分配一个共享内存区域,另一种方法是通过内核来通信

二、_REENTRANT

在一个多线程程序里,默认情况下,只有一个errno变量供所有的线程共享。在一个线程准备获取刚才的错误代码时,该变量很容易被另一个线程中的函数调用所改变。类似的问题还存在于fputs之类的函数中,这些函数通常用一个单独的全局性区域来缓存输出数据。

为解决这个问题,需要使用可重入的例程。可重入代码可以被多次调用而仍然工作正常。编写的多线程程序,通过定义宏_REENTRANT来告诉编译器我们需要可重入功能,这个宏的定义必须出现于程序中的任何#include语句之前。

_REENTRANT为我们做三件事情:

1)它会对部分函数重新定义它们的可安全重入的版本,这些函数名字一般不会发生改变,只是会在函数名后面添加_r字符串,如函数名gethostbyname变成gethostbyname_r

2stdio.h中原来以宏的形式实现的一些函数将变成可安全重入函数。

3)在error.h中定义的变量error现在将成为一个函数调用,它能够以一种安全的多线程方式来获取真正的errno的值。

 

 

 

 

三、基本函数

(1)pthread_create函数 

#include <pthread.h>

int pthread_create ( pthread_t  *thread,  pthread_attr_t  * attr,  void*  (*start_routine)(void*),  

                            void *arg );

返回值:调用成功返回“0”,如果失败则返回一个错误。

 

第一个参数:进程创建时,会分配一个唯一的PID标识,同样的,线程创建时,也会用一个指向pthread_t类型的数据类型作为新线程的标识.(线程标示符)

第二个参数:对程序的属性进行设置

第三个参数:线程将要启动执行的函数,该函数的返回值和参数都是void指针,这样就可以传递任意类型的指针

第四个参数:传递给线程将要执行的函数(第三个参数)的参数

 

 

(2)pthread_exit函数

#include <pthread.h>

void pthread_exit (void *  retval );

线程在结束时必须调用pthread_exit函数,这与一个进程在结束时要调用exit是同样的道理。

返回值:返回一个指向某个对象的指针,绝不要用它返回一个指向一个局部变量的指针,因为局部变量会在线程出现严重问题时消失得无影无踪。

 

 

(3)pthread_join函数

#include <pthread.h>

int pthread_join  (pthread_t th,   void ** thread_return  );

pthread_join相当于进程用来等待子进程的wait函数,它的作用是在线程结束后把它们归并到一起。

 

返回值:成功时返回“0”, 失败时返回一个错误代码

第一个参数:将要等待的线程,它就是pthread_create返回的那个标识符

第二个参数:是一个指针,它指向另外一个指针,而这个指针指向线程的返回值

 

 

四、简单例子

thread.c文件

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <pthread.h>

void *thread_function(void*arg);

/*message是共享的数据*/

char message[] = "Hello World";

int main(){

    int res;

    pthread_t a_thread;

    void *thread_result;

    /*NULL表示不修改线程的属性,a_thread是新线程的标识符,

        以后的对新线程的引用就使用这个标识符*/

    res = pthread_create(&a_thread, NULL, thread_function,(void*)message);

    if(res != 0){

        perror("Thread creation failed");

        exit(EXIT_FAILURE);

        }

    

    printf("waiting for thread to finish...\n");

    /*等待新线程执行完,然后合并新线程,thread_result是新线程的返回值,

        这里是"Thank you for the CPU time",pthread_exit的参数内容,

      这个函数会等到新线程结束后才返回*/

    res = pthread_join(a_thread, &thread_result);

    if(res != 0){

        perror("THread join failed");

        exit(EXIT_FAILURE); 

        }

    printf("Thread joined, it returned %s\n",(char*)thread_result);

    printf("Message is now %s\n", message);

    exit(EXIT_SUCCESS);

}

void *thread_function(void* arg){

    printf("thread_function is running. Argument was %s\n",(char*)arg);

    sleep(3);

    strcpy(message, "Bye");

    pthread_exit("Thank you for the CPU time");

    }

编译程序:gcc -D_REENTRANT   thread.c -lpthread -o thread    

运行:./thread

程序调用了pthread_create后,新线程开始执行。就是说,调用成功后,我们就有两个线程在运行。

原先的老线程将执行pthread_create后的代码,而新线程就去执行thread_function函数。

一开始,message是“Hello World”,但在新线程里,message被改成“Bye”。新线程结束后,输出的message依然是“Bye.”,

因为message是共享的数据(见上图多线程)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值