2.4 linux C 进程与多线程入门--(4)简单多线程程序


一、进程与线程:

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

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

多线程的结构:

而进程之间的通信有两种方式:(1)两个进程之间分配一个共享内存区域(2)内核通信

二、 _REENTRANT宏。

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

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

_REENTRANT为我们做三件事情:

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

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

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

三、基本函数:

(1)pthread_create()函数:

#inlcude<pthread.h>

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

(void *),void *arg);

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

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

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

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

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

(2)pthread_exit()函数:

#include<pthread.h>

void pthtead_exit(void * retval);

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

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

(3)pthread_join()函数

#include<pthread.h>

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

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

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

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

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

简单例子:

#include<stdio.h>

#include<unistd.h>

#include<stdlib.h>

#include<pthread.h>

void * thread_function(void * arg);

//message 是共享的数据

char message[];

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 是新进程的返回值

res = pthread_join(a_thread,&thread_result);

if(res! = 0)

{

perror("thread join failed");

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是共享的数据(见上图多线程)

优质内容筛选与推荐>>
1、.NET Core 首例 Office 开源跨平台组件(NPOI Core)
2、九度oj 题目1342:寻找最长合法括号序列II
3、BACnet标准初探
4、冒泡排序和去重
5、简单的表格斑马样式实现


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号