Linux下c开发 之 线程通信(转)

1.Linux“线程”

     进程与线程之间是有区别的,不过Linux内核只提供了轻量进程的支持,未实现线程模型。Linux是一种“多进程单线程”的操作系统。Linux本身只有进程的概念,而其所谓的“线程”本质上在内核里仍然是进程。

     大家知道,进程是资源分配的单位,同一进程中的多个线程共享该进程的资源(如作为共享内存的全局变量)。Linux中所谓的“线程”只是在被创建时clone了父进程的资源,因此clone出来的进程表现为“线程”,这一点一定要弄清楚。因此,Linux“线程”这个概念只有在打冒号的情况下才是最准确的。

     目前Linux中最流行的线程机制为LinuxThreads,所采用的就是线程-进程“一对一”模型,调度交给核心,而在用户级实现一个包括信号处理在内的线程管理机制。LinuxThreads由Xavier Leroy (Xavier.Leroy@inria.fr)负责开发完成,并已绑定在GLIBC中发行,它实现了一种BiCapitalized面向Linux的Posix 1003.1c “pthread”标准接口。Linuxthread可以支持Intel、Alpha、MIPS等平台上的多处理器系统。

  按照POSIX 1003.1c 标准编写的程序与Linuxthread 库相链接即可支持Linux平台上的多线程,在程序中需包含头文件pthread. h,在编译链接时使用命令:

gcc -D -REENTRANT -lpthread xxx. c

  其中-REENTRANT宏使得相关库函数(如stdio.h、errno.h中函数) 是可重入的、线程安全的(thread-safe),-lpthread则意味着链接库目录下的libpthread.a或libpthread.so文件。使用Linuxthread库需要2.0以上版本的Linux内核及相应版本的C库(libc 5.2.18、libc 5.4.12、libc 6)。

     2.“线程”控制

  线程创建

  进程被创建时,系统会为其创建一个主线程,而要在进程中创建新的线程,则可以调用pthread_create:

pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *
(start_routine)(void*), void *arg);

  start_routine为新线程的入口函数,arg为传递给start_routine的参数。

  每个线程都有自己的线程ID,以便在进程内区分。线程ID在pthread_create调用时回返给创建线程的调用者;一个线程也可以在创建后使用pthread_self()调用获取自己的线程ID:

pthread_self (void) ;

  线程退出

  线程的退出方式有三:

  (1)执行完成后隐式退出;

  (2)由线程本身显示调用pthread_exit 函数退出;

pthread_exit (void * retval) ;

  (3)被其他线程用pthread_cance函数终止:

pthread_cance (pthread_t thread) ;

  在某线程中调用此函数,可以终止由参数thread 指定的线程。

  如果一个线程要等待另一个线程的终止,可以使用pthread_join函数,该函数的作用是调用pthread_join的线程将被挂起直到线程ID为参数thread的线程终止:

pthread_join (pthread_t thread, void** threadreturn);

3.线程通信

  线程互斥

  互斥意味着“排它”,即两个线程不能同时进入被互斥保护的代码。Linux下可以通过pthread_mutex_t 定义互斥体机制完成多线程的互斥操作,该机制的作用是对某个需要互斥的部分,在进入时先得到互斥体,如果没有得到互斥体,表明互斥部分被其它线程拥有,此时欲获取互斥体的线程阻塞,直到拥有该互斥体的线程完成互斥部分的操作为止。

  下面的代码实现了对共享全局变量x 用互斥体mutex 进行保护的目的:

int x; // 进程中的全局变量
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL); //按缺省的属性初始化互斥体变量mutex
pthread_mutex_lock(&mutex); // 给互斥体变量加锁
… //对变量x 的操作
phtread_mutex_unlock(&mutex); // 给互斥体变量解除锁

  线程同步

  同步就是线程等待某个事件的发生。只有当等待的事件发生线程才继续执行,否则线程挂起并放弃处理器。当多个线程协作时,相互作用的任务必须在一定的条件下同步。

  Linux下的C语言编程有多种线程同步机制,最典型的是条件变量(condition variable)。pthread_cond_init用来创建一个条件变量,其函数原型为:

pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr);

  pthread_cond_wait和pthread_cond_timedwait用来等待条件变量被设置,值得注意的是这两个等待调用需要一个已经上锁的互斥体mutex,这是为了防止在真正进入等待状态之前别的线程有可能设置该条件变量而产生竞争。pthread_cond_wait的函数原型为:

pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);

  pthread_cond_broadcast用于设置条件变量,即使得事件发生,这样等待该事件的线程将不再阻塞:

pthread_cond_broadcast (pthread_cond_t *cond) ;

  pthread_cond_signal则用于解除某一个等待线程的阻塞状态:

pthread_cond_signal (pthread_cond_t *cond) ;

  pthread_cond_destroy 则用于释放一个条件变量的资源。

  在头文件semaphore.h 中定义的信号量则完成了互斥体和条件变量的封装,按照多线程程序设计中访问控制机制,控制对资源的同步访问,提供程序设计人员更方便的调用接口。

sem_init(sem_t *sem, int pshared, unsigned int val);

  这个函数初始化一个信号量sem 的值为val,参数pshared 是共享属性控制,表明是否在进程间共享。

sem_wait(sem_t *sem);

  调用该函数时,若sem为无状态,调用线程阻塞,等待信号量sem值增加(post )成为有信号状态;若sem为有状态,调用线程顺序执行,但信号量的值减一。

sem_post(sem_t *sem);

  调用该函数,信号量sem的值增加,可以从无信号状态变为有信号状态。

      4.实例

  下面我们还是以名的生产者/消费者问题为例来阐述Linux线程的控制和通信。一组生产者线程与一组消费者线程通过缓冲区发生联系。生产者线程将生产的产品送入缓冲区,消费者线程则从中取出产品。缓冲区有N 个,是一个环形的缓冲池。

#include <stdio.h>
#include <pthread.h>
#define BUFFER_SIZE 16 // 缓冲区数量
struct prodcons
{
// 缓冲区相关数据结构
int buffer[BUFFER_SIZE]; /* 实际数据存放的数组*/
pthread_mutex_t lock; /* 互斥体lock 用于对缓冲区的互斥操作 */
int readpos, writepos; /* 读写指针*/
pthread_cond_t notempty; /* 缓冲区非空的条件变量 */
pthread_cond_t notfull; /* 缓冲区未满的条件变量 */
};
/* 初始化缓冲区结构 */
void init(struct prodcons *b)
{
pthread_mutex_init(&b->lock, NULL);
pthread_cond_init(&b->notempty, NULL);
pthread_cond_init(&b->notfull, NULL);
b->readpos = 0;
b->writepos = 0;
}
/* 将产品放入缓冲区,这里是存入一个整数*/
void put(struct prodcons *b, int data)
{
pthread_mutex_lock(&b->lock);
/* 等待缓冲区未满*/
if ((b->writepos + 1) % BUFFER_SIZE == b->readpos)
{
pthread_cond_wait(&b->notfull, &b->lock);
}
/* 写数据,并移动指针 */
b->buffer[b->writepos] = data;
b->writepos++;
if (b->writepos > = BUFFER_SIZE)
b->writepos = 0;
/* 设置缓冲区非空的条件变量*/
pthread_cond_signal(&b->notempty);
pthread_mutex_unlock(&b->lock);
}
/* 从缓冲区中取出整数*/
int get(struct prodcons *b)
{
int data;
pthread_mutex_lock(&b->lock);
/* 等待缓冲区非空*/
if (b->writepos == b->readpos)
{
pthread_cond_wait(&b->notempty, &b->lock);
}
/* 读数据,移动读指针*/
data = b->buffer[b->readpos];
b->readpos++;
if (b->readpos > = BUFFER_SIZE)
b->readpos = 0;
/* 设置缓冲区未满的条件变量*/
pthread_cond_signal(&b->notfull);
pthread_mutex_unlock(&b->lock);
return data;
}

/* 测试:生产者线程将1 到10000 的整数送入缓冲区,消费者线
程从缓冲区中获取整数,两者都打印信息*/
#define OVER ( - 1)
struct prodcons buffer;
void *producer(void *data)
{
int n;
for (n = 0; n < 10000; n++)
{
printf("%d --->\n", n);
put(&buffer, n);
} put(&buffer, OVER);
return NULL;
}

void *consumer(void *data)
{
int d;
while (1)
{
d = get(&buffer);
if (d == OVER)
break;
printf("--->%d \n", d);
}
return NULL;
}

int main(void)
{
pthread_t th_a, th_b;
void *retval;
init(&buffer);
/* 创建生产者和消费者线程*/
pthread_create(&th_a, NULL, producer, 0);
pthread_create(&th_b, NULL, consumer, 0);
/* 等待两个线程结束*/
pthread_join(th_a, &retval);
pthread_join(th_b, &retval);
return 0;
}

  5.WIN32、VxWorks、Linux线程类比

  目前为止,笔者已经创作了《基于嵌入式操作系统VxWorks的多任务并发程序设计》(《软件报》2006年5~12期连载)、《深入浅出Win32多线程程序设计》(天极网技术专题)系列,我们来找出这两个系列文章与本文的共通点。

   看待技术问题要瞄准其本质,不管是Linux、VxWorks还是WIN32,其涉及到多线程的部分都是那些内容,无非就是线程控制和线程通信,它们的许多函数只是名称不同,其实质含义是等价的,下面我们来列个三大操作系统共同点详细表单:

事项WIN32VxWorksLinux
线程创建CreateThreadtaskSpawnpthread_create
线程终止执行完成后退出;线程自身调用ExitThread函数即终止自己;被其他线程调用函数TerminateThread函数执行完成后退出;由线程本身调用exit退出;被其他线程调用函数taskDelete终止执行完成后退出;由线程本身调用pthread_exit 退出;被其他线程调用函数pthread_cance终止
获取线程IDGetCurrentThreadIdtaskIdSelfpthread_self
创建互斥CreateMutexsemMCreatepthread_mutex_init
获取互斥WaitForSingleObject、WaitForMultipleObjectssemTakepthread_mutex_lock
释放互斥ReleaseMutexsemGivephtread_mutex_unlock
创建信号量CreateSemaphoresemBCreate、semCCreatesem_init
等待信号量WaitForSingleObjectsemTakesem_wait
释放信号量ReleaseSemaphoresemGivesem_post

   6.小结

  本章讲述了Linux下多线程的控制及线程间通信编程方法,给出了一个生产者/消费者的实例,并将Linux的多线程与WIN32、VxWorks多线程进行了类比,总结了一般规律。鉴于多线程编程已成为开发并发应用程序的主流方法,学好本章的意义也便不言自明。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/254968.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HDU 1028 Ignatius and the Princess III

//强行递推。 xx[i][j]表示i数中第j个开头的组合种类。 /* 最终结果[i]为 sum of(xx[i][j]) (j from 1 to i); xx[i][j]sum of (xx[i-j][k]) (k from 1 to j); 例如 xx[10][4]xx[6][1]xx[6][2]xx[6][3]xx[6][4]; xx[6][1] 1; 6111111; xx[6][2]3; 6222, 62211, 621111; xx[…

HALCON示例程序measure_metal_part_id.hdev使用xld边缘拟合检测零件加工是否合格

HALCON示例程序measure_metal_part_id.hdev使用xld边缘拟合检测零件加工是否合格 示例程序源码&#xff08;加注释&#xff09; 关于显示类函数解释 dev_update_off () Imagefiles : [‘metal-parts/metal-part-model-01’,‘metal-parts/metal-parts-01’,‘metal-parts/meta…

编写批处理文件-------基础

第一、Windows bat 批处理文件 编写 如何编写批处理文件 批处理文件&#xff08;batch file&#xff09;包含一系列 DOS命令&#xff0c;通常用于自动执行重复性任务。 用户只需双击批处理文件便可执行任务&#xff0c;而无需重复输入相同指令。编写批处理文件非常简单&#xf…

主控芯片

主控芯片&#xff1a; 主控芯片里有310&#xff0c;320,3288&#xff0c;288,318&#xff0c;333&#xff0c;345&#xff0c;7501, 其中310是中星微发展比较早&#xff0c;比较成熟的芯片。在现在一般应用在水晶夹子之类的低端产品上。 3288也是低端芯片&#xff0c;318&…

MPEG2、H.263、H.264协议效率对比

[摘录]1.1 MPEG2、H.263、H.264协议效率对比ITUT中定义的双向视频通信协议族包括&#xff1a;H.320、H.323&#xff0c;这两个协议族中&#xff0c;包含了很多子协议&#xff0c;例如音频编码协议、视频编码协议等&#xff0c;其中视频编码包括&#xff1a;H.261、H.263、H.264…

WebService SOAP、Restful和HTTP(post/get)请求区别

web service&#xff08;SOAP&#xff09; Webservice的一个最基本的目的就是提供在各个不同平台的不同应用系统的协同工作能力。 Web service 就是一个应用程序&#xff0c;它向外界暴露出一个能够通过Web进行调用的API。 SOAP是一种简单基于xml的轻量协议&#xff0c;用户web…

Block的循环引用详解

1.首先我们创建了一个网络请求工具类 然后storyboard里面去创建了一个导航控制器 并且把它设置为初始控制器 然后拖入一个bar button &#xff0d;&#xff0d;show&#xff0d;&#xff0d;到自带的控制器 这个时候运行代码的结果是 x 显然这个时候没有造成循环引用 为什…

HALCON示例程序measure_pump.hdev螺纹孔位置与尺寸测量

HALCON示例程序measure_pump.hdev螺纹孔位置与尺寸测量 示例程序源码&#xff08;加注释&#xff09; 关于显示类函数解释 dev_update_var (‘off’) dev_update_off () read_image (Image, ‘pumpe’) get_image_size (Image, Width, Height) dev_close_window () dev_open_…

计算机视觉和图形学中的摄像机内参数矩阵详解

在计算机视觉和图形学中都有“摄像机内参数矩阵”这个概念&#xff0c;其含义大致相同&#xff0c;但在实际使用过程中&#xff0c;这两个矩阵却相差甚远。在增强现实中&#xff0c;为了使计算机绘制的虚拟物体和真实环境图像对其&#xff0c;需要令虚拟摄像机的内参数和真实摄…

c#和html方法互调

具体见连接&#xff1a;https://www.cnblogs.com/zeroLove/p/3912460.html转载于:https://www.cnblogs.com/gaara-zhang/p/8746403.html

数据库基础杂记

sql,Structured Query Language结构化查询语言。SQL 是一门 ANSI(美国国家标准局) 的标准计算机语言&#xff0c;用来访问和操作数据库系统。SQL 语句用于取回和更新数据库中的数据。SQL 可与数据库程序协同工作&#xff0c;比如 MS Access、DB2、Informix、MS SQL Server、Ora…

很有用的X264和ffmpeg的设置

很有用的X264和FFMPEG的设置 http://www.360doc.com/content/11/0209/16/3705984_91612512.shtml 点击打开链接

HALCON示例程序measure_ring.hdev齿轮齿宽度测量

HALCON示例程序measure_ring.hdev齿轮齿宽度测量 示例程序源码&#xff08;加注释&#xff09; 关于显示类函数解释 read_image (Image, ‘rings_and_nuts’) dev_close_window () dev_open_window_fit_image (Image, 0, 0, 640, 640, WindowHandle) set_display_font (Windo…

基于RBGD的mapping

最近学习RGBD的SLAM&#xff0c;收集了两个RGBD的mapping的开源工具包 1.RGBDSlam2 a.安装方法&#xff1a; #准备工作空间 source /opt/ros/indigo/setup.bash mkdir -p ~/rgbdslam_catkin_ws/src cd ~/rgbdslam_catkin_ws/src catkin_init_workspace cd ~/rgbdslam_catkin_ws…

【瓜分5000元奖金】Wannafly挑战赛13

链接&#xff1a;https://www.nowcoder.com/acm/contest/80/A来源&#xff1a;牛客网 zzy的小号 时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒空间限制&#xff1a;C/C 262144K&#xff0c;其他语言524288K64bit IO Format: %lld题目描述 学家zzy根据字体的特点&#…

X264参数设定详细解释

x264 core:65 r1074M b6bb3d4 Syntax: x264 [options] -o outfile infile [widthxheight] 语法(命令行写法)&#xff1a;x264 [参数] -o 输出文件名 输入文件名 [宽x高] 范例&#xff1a; x264 --crf 26 --ref 3 --mixed-refs --bframes 3 --b-adapt 2 --b-pyramid --weightb -…

20145217《网络对抗》 恶意代码分析

20145217《网络对抗》 免杀原理与实践 知识点学习总结 进行恶意代码分析之前必须具备以下知识&#xff1a;编程、汇编/反汇编、网络基本知识、PE文件结构以及一些常用行为分析软件。 一、在一个已经感染了恶意代码的机器上如何找到病毒文件&#xff1f; 找到恶意代码才能对其分…

HALCON示例程序measure_screw.hdev螺纹尺寸测量

HALCON示例程序measure_screw.hdev螺纹尺寸测量 示例程序源码&#xff08;加注释&#xff09; 关于显示类函数解释 dev_update_off () read_image (Image, ‘screw_thread’) get_image_pointer1 (Image, Pointer, Type, Width, Height) dev_close_window () dev_open_window…

边工作边刷题:70天一遍leetcode: day 97-2

Design Hit Counter 要点&#xff1a;因为是second granularity&#xff0c;所以可以用以秒为单位的circular buffer方法。这题简单在只需要count过去300秒的&#xff0c;增加难度可以count过去秒&#xff0c;分钟&#xff0c;小时。 2个时间点都有可能更新超时的统计&#xff…

cvRemap 对图像进行普通几何变换

cvRemap 对图像进行普通几何变换 函数 cvRemap 利用下面指定的矩阵变换输入图像:   dst(x,y)<-src(mapx(x,y),mapy(x,y))   与其它几何变换类似&#xff0c;可以使用一些插值方法&#xff08;由用户指定&#xff0c;同cvResize&#xff09;来计算非整数坐标的像素值 vo…