文档章节

C语言的线程不同步问题的研究

断桥残雪断桥残雪
 断桥残雪断桥残雪
发布于 2015/07/31 14:37
字数 1211
阅读 149
收藏 1

线程的概念

线程就是运行在进程上下文的逻辑流。程序是由进程中的线程构成的,现代操作系统允许我们在一个进程中使用多个线程,线程由内核自动调度。每个线程有自己的线程上下文,包括一个唯一的整数线程ID(thread ID,tid),栈,栈指针,程序计数器,通用目的寄存器和条件码。所有运行在同一个进程上的线程共享该进程的整个虚拟地址空间。每一个进程开始生命周期时都是单一线程,这个线程称为主线程。在某一时刻,主线程创建一个对等线程,从这个时间点开始,两个线程就会并发运行。

线程执行不同于进程执行,因为一个线程的上下文要比一个进程的上下文小的多,线程的上下文切换较进程的上下文切换容易得多,和一个进程相关的线程组成一个线程池,独立于其他进程创建的线程。主线程和其他线程的区别仅仅在于它总是进程中第一个运行的线程。对等线程池的概念的主要影响是,一个线程可以杀死它的任何对等线程,或者等待它的任何对等线程终止。另外,每个对等线程都能读写相同的共享数据。

Posix线程(Pthreads)是在C程序中处理线程的一个标准接口,它最早出现在1995年,而且在大多数unix系统都可用。它可以允许程序创建/杀死/回收线程,与对等线程安全地共享数据,还可以通知对等线程系统状态的变化。

线程不同步案例

线程很有吸引力的一方面是因为多个线程可以很容易共享相同的程序变量。然而,这种共享也很棘手,为了编写正确的现成化程序,我们必须对所谓的共享以及如何工作有所了解。

线程存储器模型,根据存储类型分有三种:1.全局变量,全局变量定义在函数外面,在运行时,虚拟存储器的读/写区域只包含每个全局变量的一个实例,任何线程可以引用。2.本地自动变量,本地自动变量就是定义在函数内部但是没有static属性的变量,在运行时,每个线程的栈都包含它自己的所有本地自动变量的实例。即使多个线程执行同一个线程例程时也是如此。3.本地静态变量,函数内部并有static属性的变量。和全局变量一样,虚拟存储器的读/写区域只包含在程序中声明的每个本地静态变量的一个实例。

下面一段代码演示了共享变量的同步错误的可能性。

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
void *thread(void *vargp);
volatile int cnt=0;
int main(int argc,char* argv[])
{
    int niters;
    pthread_t pt1,pt2;
    if(argc!=2) {
        fprintf(stderr,"usage:%s <niters>\n",argv[0]);
        return 1;
    }
    niters=atoi(argv[1]);
    pthread_create(&pt1,NULL,thread,&niters);
    pthread_create(&pt2,NULL,thread,&niters);
    pthread_join(pt1,NULL);
    pthread_join(pt2,NULL);
    if(cnt!=(2*niters)) {
        fprintf(stdout,"Boom,cnt=%d\n",cnt);
        return 0;
    }
    else {
        fprintf(stdout,"OK cnt=%d\n",cnt);
        return 0;
    }
}
void *thread(void *vargp)
{
    int i,niters=*((int *)vargp);
    for(i=0;i<niters;i++)
        cnt++;
    return NULL;
}

我们写出这个文件的简单Makefile文件:

# this is a makefile!
main.out: main.c
    gcc main.c -o main.out -pthread

注意,C语言的线程程序编译时需要加上-pthread选项。

我们执行结果如下:

zzw@zzw-ThinkPad-Edge-E430c:~/c/thread/demo1$ ./main.out 10000
Boom,cnt=11493
zzw@zzw-ThinkPad-Edge-E430c:~/c/thread/demo1$ ./main.out 10000
Boom,cnt=12066
zzw@zzw-ThinkPad-Edge-E430c:~/c/thread/demo1$ ./main.out 10000
Boom,cnt=11759
zzw@zzw-ThinkPad-Edge-E430c:~/c/thread/demo1$ ./main.out 10000
Boom,cnt=10908

可以看到,四次执行都发生了同步错误,即共享变量没有被正确共享。

其实,线程函数代码thread部分我们可以分为以下五个部分:

  1. 在循环头部的指令块

  2. 加载共享变量cnt到寄存器%eax的指令,这里%eax表示线程i中的寄存器%eax的值

  3. 更新%eax的指令

  4. 将%eax的更新值存回到共享变量cnt的指令

  5. 循环尾部的指令块

总结

因此,我们很容易看到,从第2步到第4步是不安全区,即这三步是不能被其他线程打断的,需要锁定,即是个原子操作,只有这样才能保证程序的全局变量能够正确共享。而上面的代码中并没有体现这一点,因此无法正确运行结果。

© 著作权归作者所有

断桥残雪断桥残雪
粉丝 53
博文 139
码字总数 94909
作品 0
广州
程序员
私信 提问
一名3年工作经验的Java程序员应该具备的技能

一名3年工作经验的Java程序员应该具备的技能,这可能是Java程序员们比较关心的内容。我这里要说明一下,以下列举的内容不是都要会的东西—-但是如果你掌握得越多,最终能得到的评价、拿到的薪...

JackFace
2016/08/08
397
0
C++ epoll网络编程 buffer缓存

最近研究代码发现一些问题,诚意请教大牛,最近研究了一些C++工程项目,现在的网络层一般使用epoll轮询操作,现在一般使用多个线程,一个网络线程,其余逻辑线程,逻辑线程中当有socket要发送...

曾需缘
2014/10/19
742
2
面试感悟----一名3年工作经验的程序员应该具备的技能

关于程序员的几个阶段 每个程序员、或者说每个工作者都应该有自己的职业规划,如果看到这里的朋友没有自己的职业规划,希望你可以思考一下自己的将来。 LZ常常思考自己的未来,也从自己的思考...

-wangming-
2016/03/11
381
5
C#读写者线程(用AutoResetEvent实现同步)

本博客(http://blog.csdn.net/livelylittlefish)贴出作者(三二一、小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正! C#读写者线程(用AutoResetEvent实现同步) 最近研究C#中的多...

晨曦之光
2012/03/09
234
0
下面的Java代码会产生线程死锁,谁能告诉我为什么会死锁?如何解决?

今日在研究线程同步和通信方面的问题,出现了线程死锁。我在这方面思路不是很清晰,请大哥们告诉我出现死锁的原因,和解决问题的步骤。谢谢了。 这道题目是这样的。 1线程连续执行10次后2线程...

Enterprize
2015/05/10
1K
4

没有更多内容

加载失败,请刷新页面

加载更多

java快递电子面单打印接口对接demo

之前的后天管理系统的电子面单打印使用的是灵通打单。 使用相对比较麻烦,需要到处Excel之后再导入,麻烦。 快递鸟有电子面单api,后台系统直接对接很是方便,不过也遇到了好些问题。 不难是...

程序的小猿
19分钟前
3
0
fasjtjson文档

https://github.com/alibaba/fastjson/wiki/JSONField

jirak
19分钟前
3
0
Mybatis中插入多条记录

Oracle数据库 实现方法 <insert id="saveWithdrawLog"> INSERT ALL INTO OSM_TRADE_DETAIL(SID,MBR_ID,USR_ID,TRADE_MONEY,TRADE_TYPE,TRADE_TIME,TRADE_WAY,PAY_ID) VALUES(#{si......

豫华商
20分钟前
3
0
Flink on YARN(下):常见问题与排查思路

作者:杨弢(搏远) Flink 支持 Standalone 独立部署和 YARN、Kubernetes、Mesos 等集群部署模式,其中 YARN 集群部署模式在国内的应用越来越广泛。Flink 社区将推出 Flink on YARN 应用解读...

开源中国小二
22分钟前
2
0
技术沙龙|京东云端到端多媒体关键技术揭秘

编者按:从带来更高编码效率、更好的用户体验的京享高清,到直播架构与网络演进优化,从而为用户带来更流畅的观看体验,以及运维系统的异常自动修复和高弹性的多媒体存储架构,一层一层展示出...

京东云技术新知
22分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部