多线程的基本问题
年初面试了不少移动端应用开发人员,面试过程问到一些多线程编程需要注意一些问题,主要是像考察一下对多线程安全有没有概念,因为在接手其他人的项目时一直被坑,多线程下出各种乱七八糟稳定性问题。具体问题一般就简化为两个:
1,如何实现一个线程安全的单例(singleton)。
2,有两个线程,线程1和线程2,同时对同一个变量i自加(i++)10000次,两个线程都完成退出时,变量i的值是多少?为什么?
这两个问题,想考察的仅仅是线程同步安全问题而已,主要能提到需要注意这方面的问题,就认为过了。令人失望的是,大多人都没能大体正确的回答这两个问题。关于单例问题,有空另外讨论。对第二个问题,大多人在思考一番后回答是20000,没有附加条件,完全没有锁同步,线程安全的概念。提示如果完全不加锁同步,不太可能结果为20000,也不能解释为什么。往往这个时候,我建议回去的时候,做一个实验,看看实际结果。难道是要求太高了?
不管怎么样,今天我们来做一个实验看看,不加锁同步情况下,两个线程同时操作同一个变量自加 1000000次,看看结果如何。
不考虑线程间同步变量累加结果图
测试代码如下:
//
// threadNonSyncTest.c
// mempool
//
// Created by gjwang on 10/21/15.
// Copyright (c) 2015 gjwang. All rights reserved.
//
//https://github.com/gjwang/mempool/blob/master/mempool/threadNonSyncTest.c
#include <stdio.h>
#include <pthread.h>
#include "threadNonSyncTest.h"
#ifndef _INT64_T
#define _INT64_T
typedef long long int64_t;
#endif
#define NUM_THREADS (2)
static int64_t globalCount = 0;
static const int64_t addPerforTimes = 1000000;
static const int testTimes = 1000;
void *thread_work(void *argument)
{
for (int64_t i = 0; i < addPerforTimes; i++) {
globalCount++;
}
return NULL;
}
void threadNonSyncTest(){
pthread_t threads[NUM_THREADS];
globalCount = 0;
int index;
for (index = 0; index < NUM_THREADS; ++index) {
pthread_create(&threads[index], NULL, thread_work, NULL);
}
for (index = 0; index < NUM_THREADS; ++index) {
pthread_join(threads[index], NULL);
}
printf("globalCount=%lld\n", globalCount);
}
int main(int argc, const char * argv[]) {
int i;
for (i = 0; i<testTimes; i++) {
threadNonSyncTest();
printf("%lld\n", globalCount);
}
}
编译并执行:gcc -O0 threadNonSyncTest.c -o threadNonSyncTest && ./threadNonSyncTest
代码github地址:
https://github.com/gjwang/mempool/blob/master/mempool/threadNonSyncTest.h
https://github.com/gjwang/mempool/blob/master/mempool/threadNonSyncTest.c
说明:如果使用-O2编译,有很大的几率看到“正确的”结果,因为现在的CPU很强悍,另一个线程可能还没启动,第一个已经完成了。