1.初始化一个函数指针数组?
函数指针数组的定义
const double * f1(const double ar[], int n);
const double * f2(const double [], int);
const double * f3(const double *, int);
按指针函数定义,如果定义一个指针表示函数f1,则为:
const double * (*p1)(const double *, int);
指向f1,*p1等同于f1:
const double * (*p1)(const double *, int) = f1;
p1虽然是f1的地址,但是在函数调用的时候,两者等同,所以输出与f1相同,要想输出函数f1()的地址,需要&p1。
函数指针数组
const double * (*pa[3])(const double *, int) = {f1, f2, f3};
首先看优先级,[]最高,所以可以变为:
const double * (* (pa[3]))(const double *, int) = {f1, f2, f3};
这样子就好看了,类似于数组的定义,当pa[0]=f1, pa[2]=f2, pa[3]=f3的时候,定义的时候就是double pa[3]={f1, f2, f3}. 再把前面那些修饰符加上,就是函数指针数组的定义加初始化。再解释就方便了,pa是个数组,数组有三个元素,三个元素分别指向f1, f2, f3,拆开看跟之前的单个定义一样(比如pa[0]等价于p1)。
http://www.classnotes.cn/2095.html
2.实现一个死锁?
目前想到两种简单的写法:
- 一种是单线程对一个资源重复申请上锁;
#include <iostream>
#include <thread>
#include <mutex>
#include <unistd.h>
using namespace std;
int data = 1;
mutex mt1,mt2;
void a2() {
data = data * data;
mt1.lock(); //第二次申请对mt1上锁,但是上不上去
cout<<data<<endl;
mt1.unlock();
}
void a1() {
mt1.lock(); //第一次对mt1上锁
data = data+1;
a2();
cout<<data<<endl;
mt1.unlock();
}
int main() {
thread t1(a1);
t1.join();
cout<<"main here"<<endl;
return 0;
}
- 第二种是两个线程对两个资源申请上锁,形成环路。
#include <iostream>
#include <thread>
#include <mutex>
#include <unistd.h>
using namespace std;
int data = 1;
mutex mt1,mt2;
void a2() {
mt2.lock();
sleep(1);
data = data * data;
mt1.lock(); //此时a1已经对mt1上锁,所以要等待
cout<<data<<endl;
mt1.unlock();
mt2.unlock();
}
void a1() {
mt1.lock();
sleep(1);
data = data+1;
mt2.lock(); //此时a2已经对mt2上锁,所以要等待
cout<<data<<endl;
mt2.unlock();
mt1.unlock();
}
int main() {
thread t2(a2);
thread t1(a1);
t1.join();
t2.join();
cout<<"main here"<<endl; //要t1线程、t2线程都执行完毕后才会执行
return 0;
}
3.项目的难点在哪里?你会如何优化?为什么当时不优化?
可优化点:
- 增加支持异步调用接口;
- 支持横向拓展,增加服务注册、服务发现和负载均衡;
- 修改接口为
dlopen
插件式,支持sdk的动态拓展,对外暴露统一的服务接口。
4.第三方调用微信登录验证发生了什么?
第一步:用户同意授权,获取code
第二步:通过code换取网页授权access_token
第三步:刷新access_token(如果需要)
第四步:拉取用户信息(需scope为 snsapi_userinfo)
5.微信登录二维码机制?你会如何进行技术选型?
扫码登录可以分为三个阶段:待扫描、已扫描待确认、已确认。
- 待扫描阶段
待扫描阶段也就是流程图中 1~5 阶段,即生成二维码阶段,这个阶段跟移动端没有关系,是 PC 端跟服务端的交互过程。
首先 PC 端携带设备信息想服务端发起生成二维码请求,服务端会生成唯一的二维码 ID,你可以理解为 UUID,并且将 二维码 ID 跟 PC 设备信息关联起来,这跟移动端登录有点相似。
PC 端接受到二维码 ID 之后,将二维码 ID 以二维码的形式展示,等待移动端扫码。此时在 PC 端会启动一个定时器,轮询查询二维码的状态。如果移动端未扫描的话,那么一段时间后二维码将会失效。
- 已扫描待确认阶段
流程图中第 6 ~ 10 阶段,我们在 PC 端登录微信时,手机扫码后,PC 端的二维码会变成已扫码,请在手机端确认。这个阶段是移动端跟服务端交互的过程。
首先移动端扫描二维码,获取二维码 ID,然后将手机端登录的信息凭证(token)和 二维码 ID 作为参数发送给服务端,此时的手机一定是登录的,不存在没登录的情况。
服务端接受请求后,会将 token 与二维码 ID 关联,为什么需要关联呢?你想想,我们使用微信时,移动端退出, PC 端是不是也需要退出,这个关联就有点把子作用了。然后会生成一个一次性 token,这个 token 会返回给移动端,一次性 token 用作确认时候的凭证。
PC 端的定时器,会轮询到二维码的状态已经发生变化,会将 PC 端的二维码更新为已扫描,请确认。
- 已确认
流程图中的 第 11 ~ 15 步骤,这是扫码登录的最后阶段,移动端携带上一步骤中获取的临时 token ,确认登录,服务端校对完成后,会更新二维码状态,并且给 PC 端生成一个正式的 token ,后续 PC 端就是持有这个 token 访问服务端。
PC 端的定时器,轮询到了二维码状态为登录状态,并且会获取到了生成的 token ,完成登录,后续访问都基于 token 完成。
在服务器端会跟手机端一样,维护着 token 跟二维码、PC 设备信息、账号等信息。
到此,二维码扫描登录原理就差不多了,二维码扫描登录在原理上不难理解,跟 OAuth2.0 有一丝的相似之处,但是实现起来可能就比较复杂。
使用OAuth进行认证和授权的过程如下所示:
用户想操作存放在服务提供方的资源。
用户登录客户端向服务提供方请求一个临时令牌。
服务提供方验证客户端的身份后,授予一个临时令牌。
客户端获得临时令牌后,将用户引导至服务提供方的授权页面请求用户授权。在这个过程中将临时令牌和客户端的回调连接发送给服务提供方。
用户在服务提供方的网页上输入用户名和密码,然后授权该客户端访问所请求的资源。
授权成功后,服务提供方引导用户返回客户端的网页。
客户端根据临时令牌从服务提供方那里获取访问令牌。
服务提供方根据临时令牌和用户的授权情况授予客户端访问令牌。
客户端使用获取的访问令牌访问存放在服务提供方上的受保护的资源。