Selected interview questions and answers in 2020 (1)

1. In the ACM competition, a team consists of three players. Now there are N+M students, of which N students are good at algorithms, and the remaining M students are good at programming. These students have to participate in the ACM competition. Their coach Each team is required to have at least one student who is good at algorithms and one student who is good at programming. How many teams can these students form?

Input: Input two integers M and N, where 1<N, M<10000000
Output: the maximum number of teams that can be formed

#include <iostream>
using namespace std;
 
int main()
{
    
    
    int cnt = 0,n,m;
    cout << "输入N个擅长算法的,M个擅长编程的:" << endl;
    cin >> n >> m;
    while(n!=0&&m!=0&&m+n!=2){
    
    
        if(n>=m){
    
    
            n = n-2;
            m = m-1;
            cnt++;
        }
        else if(n<m){
    
    
            m = m-2;
            n = n-1;
            cnt++;
        }
    }
    cout << "最大组对数量" << cnt << endl;
    return 0;
}

2. What is idempotence

The concept of idempotence: In general terms, idempotence means that no matter how many repeated operations are performed, the same result is achieved.

3. What are idempotent operations in REST requests

GET, PUT, and DELETE are all idempotent operations, but POST is not an
analysis.
First of all, GET requests are well understood. If you query resources multiple times, the results of this implementation are the same.
The idempotence of the PUT request can be understood in this way. Modifying A to B, its first request value becomes B, and then performing this operation many times, the final result is still B, which is the same as the result of one execution, so PUT It is an idempotent operation.
In the same way, the DELETE operation can be understood. After the resource is deleted for the first time, the delete request is made multiple times later, and the final result is the same, and the resource is deleted.
POST is not an idempotent operation, because one request adds a new resource, and a second request adds two new resources. Multiple requests will produce different results, so POST is not an idempotent operation.

4. Distinguish the use of POST and PUT based on idempotence

Can be distinguished according to idempotent (idempotent).
To give a simple example, if there is a blog system that provides a Web API, the mode is like this http://superblogging/blogs/{blog-name}, very simple, replace {blog-name} with our blog name, go to This URL sends an HTTP PUT or POST request. The body part of HTTP is the blog post. This is a very simple REST API example.
Should we use the PUT method or the POST method?
Depends on whether the behavior of this REST service is idempotent, if we send two http://superblogging/blogs/post/Sample requests, what kind of behavior is on the server side? If two blog posts are generated, it means that this service is not idempotent, because multiple use has side effects; if the first request is overwritten by the latter request, then the service is idempotent. In the former case, the POST method should be used, and in the latter case, the PUT method should be used.

5. The shortcomings of CAS and their solutions.

The shortcomings of CAS are like ABA problem, spin lock consumption problem, multivariable sharing consistency problem.
1.ABA:
Problem description: Thread t1 changes its value from A to B, and then from B to A. At the same time, a thread t2 wants to change the value from A to C. But when CAS checks, it will find that there is no change, but in fact it has changed. May cause missing data.
Solution: CAS is still similar to optimistic locking, adding a version number or timestamp to it in the same way as optimistic locking of data, such as AtomicStampedReference
2. Spin consumes resources:
Problem description: When multiple threads compete for the same resource, if spin If it has been unsuccessful, it will keep occupying the CPU.
Solution: Destroy the for infinite loop. When a certain time or number of times is exceeded, return will exit. The LongAddr added in JDK8 is similar to ConcurrentHashMap. When multiple threads compete, the granularity is reduced, and a variable is split into multiple variables to achieve the effect of multiple threads accessing multiple resources. Finally, sum is called to combine them.
Although both base and cells are volatile modified, it feels that the sum operation is not locked, and the result of sum may not be so accurate.
2. Multi-variable sharing consistency problem:
Solution: CAS operation is for one variable, if you operate on multiple variables,

  1. It can be solved with a lock.
  2. Packaged into object classes to solve.
    Insert picture description here
    (More free C/C++, Linux, Nginx, ZeroMQ, MySQL, Redis, fastdfs, MongoDB, ZK, streaming media, CDN, P2P, K8S, Docker, TCP/IP, coroutine, DPDK, etc. multiple knowledge points dry goods Learning materials plus group 960994558)

6. B+ tree features

(1) The number of keywords of each node is equal to the number of children. The keywords of all non-lowest inner nodes are the largest keywords on the corresponding subtree, and the lowermost inner nodes contain all keywords .
(2) Except for the root node, each internal node has up to m children. [3]
(3) All leaf nodes are at the same level of the tree structure and do not contain any information (can be regarded as external nodes or nodes that fail to search). Therefore, the tree structure is always balanced in tree height.

7. Explain in detail the isolation of transactions.

Isolation of
transactions In order to ensure the isolation of transactions, we can naturally design transactions to be single-threaded. In this way, the efficiency will be extremely low. In order to ensure isolation without losing efficiency, we divide the loss of isolation into three situations .
Dirty read: read the data of another uncommitted transaction.
Phantom read: The table has been read once during a transaction. At this time, another transaction commit happens to cause the transaction to read the table again inconsistently. (Table impact)
Non-repeatable read: The data of a has been read once during a transaction, and another transaction commits at this time, which causes the transaction to read the data of a again inconsistently.
Four isolation levels are introduced for these three situations.
Four isolation levels:
Read uncommitted-does not prevent any isolation problems, with dirty read/non-repeatability/phantom read (phantom read) problems
Read committed-can prevent dirty read problems, But it cannot prevent non-repeatability/phantom read (phantom read) problems
Repeatable read-can prevent dirty read/non-repeatable read problems, but cannot prevent virtual read (phantom read) problems
Serializable-the database is designed as a single-threaded database, which can prevent the above All issues
These four isolation levels increase security. Diminishing efficiency

8. Knowing that a function rand7() can generate random numbers from 1-7, please give a function that can generate random numbers from 1-10. The solution is based on a method called rejection sampling. The main idea is that as long as a random number within the target range is generated, it is returned directly. If the generated random number is not within the target range, discard the value and resample. Since the numbers in the target range are selected with equal probability, such a uniform distribution is generated.

Obviously rand7 needs to be executed at least twice, otherwise the number 1-10 will not be generated. By running rand7 twice, integers from 1-49 can be generated,
Insert picture description here

Since 49 is not a multiple of 10, we need to discard some values. The range of numbers we want is 1-40. If it is not in this range, discard and resample.

Code:

int rand10() {
    
    
  int row, col, idx;
  do {
    
    
    row = rand7();
    col = rand7();
    idx = col + (row-1)*7;
  } while (idx > 40);
  return 1 + (idx-1)%10;
}

Since the row range is 1-7 and the col range is 1-7, the idx value range is 1-49. Values ​​greater than 40 are discarded, so that the remaining numbers in the range of 1-40 are returned by modulo. Let's calculate the expected value of the number of sampling times that meets the range of 1-40:
Insert picture description here

9. Please explain what optimization measures are available for the thread pool.

The higher the proportion of thread waiting time, the more threads are needed. The higher the proportion of thread CPU time, the fewer threads are needed.
If you are a CPU-intensive operation, then the number of threads is the same as the number of CPU cores, avoiding a lot of useless switching thread context.
If you are IO-intensive and need a lot of waiting, then the number of threads can be set more, for example Multiply CPU cores by 2.

10. C++11 three ways to create threads

  1. Through the function
    thread: standard library class
    join: block the main thread and wait
// MultiThread.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include<iostream>
#include<vector>
#include<map>
#include<string> 
#include<thread>

using namespace std;
void myPrint()
{
    
    
	cout << "线程开始运行" << endl;
	cout << "线程运行结束了" << endl;
}

int main()
{
    
    
	std::thread my2Obj(myPrint);  // 可调用对象
	my2Obj.join();// 主线程阻塞在这,并等待myPrint()执行完
	cout << "wangtao" << endl;
    return 0;
}

detach(): completely separate the main thread and the child thread, the child thread will reside in the background and run, and will be taken over by the C++ runtime library and lose control

void myPrint()
{
    
    
	cout << "线程开始运行1" << endl;
	cout << "线程开始运行2" << endl;
	cout << "线程开始运行3" << endl;
	cout << "线程开始运行4" << endl;
	cout << "线程开始运行5" << endl;
	cout << "线程开始运行6" << endl;
	cout << "线程开始运行7" << endl;
	cout << "线程开始运行8" << endl;
	cout << "线程开始运行9" << endl;

}

int main()
{
    
    
	std::thread my2Obj(myPrint); // 主线程阻塞在这,并等待myPrint()执行完
	my2Obj.detach();
	cout << "wangtao1" << endl;
	cout << "wangtao2" << endl;
	cout << "wangtao3" << endl;
	cout << "wangtao4" << endl;
	cout << "wangtao5" << endl;
	cout << "wangtao6" << endl;
	cout << "wangtao7" << endl;
	cout << "wangtao8" << endl;
    return 0;
}

joinable(): Determine whether you can successfully use join() or detach()

Program description: Join cannot be implemented after detach

int main()
{
    
    
	std::thread my2Obj(myPrint); // 主线程阻塞在这,并等待myPrint()执行完
	if (my2Obj.joinable()){
    
    
		cout << "1:joinable() == true" << endl;
	}
	else {
    
    
		cout << "1:joinable() == false" << endl;
	}
	my2Obj.detach();

	if (my2Obj.joinable()) {
    
    
		cout << "2:joinable() == true" << endl;
	}
	else {
    
    
		cout << "2:joinable() == false" << endl;
	}
	cout << "wangtao1" << endl;
	cout << "wangtao2" << endl;
	cout << "wangtao3" << endl;
	cout << "wangtao4" << endl;
	cout << "wangtao5" << endl;
	cout << "wangtao6" << endl;
	cout << "wangtao7" << endl;
	cout << "wangtao8" << endl;
    return 0;
}

int main()
{
    
    
	std::thread my2Obj(myPrint); // 主线程阻塞在这,并等待myPrint()执行完
	if (my2Obj.joinable()){
    
    
		my2Obj.join();
	}
	cout << "wangtao1" << endl;
	cout << "wangtao2" << endl;
	cout << "wangtao3" << endl;
	cout << "wangtao4" << endl;
	cout << "wangtao5" << endl;
	cout << "wangtao6" << endl;
	cout << "wangtao7" << endl;
	cout << "wangtao8" << endl;
    return 0;
}

2. Create thread through class object

class CObject
{
    
    
public:
	void operator ()() {
    
    
		cout << "线程开始运行" << endl;
		cout << "线程结束运行" << endl;
	}
};


int main()
{
    
    
	CObject obj;
	std::thread my2Obj(obj); // 主线程阻塞在这,并等待myPrint()执行完
	if (my2Obj.joinable()){
    
    
		my2Obj.join();
	}
	cout << "see you " << endl;
	
    return 0;
}


class CObject
{
    
    
	int& m_obj;
public:
	CObject(int& i) :m_obj(i) {
    
    }
	void operator ()() {
    
     // 不带参数
		cout << "线程开始运行1" << endl;
		cout << "线程开始运行2" << endl;
		cout << "线程开始运行3" << endl;
		cout << "线程开始运行4" << endl;
		cout << "线程开始运行5" << endl;
	}
};
int main()
{
    
    
	int i = 6;
	CObject obj(i);
	std::thread my2Obj(obj); // 主线程阻塞在这,并等待myPrint()执行完
	if (my2Obj.joinable()){
    
    
		my2Obj.detach();
	}
	cout << "see you " << endl;
	
    return 0;
}

The object is destroyed when the main thread ends with detach(). Can the member functions of the child threads be called?
The object here will be copied to the child thread. When the main thread ends, the copied child thread object will not be destroyed.
As long as there is no reference, the pointer will not cause problems.

Verify whether the object is copied to the child thread by copying the constructor and destructor

// MultiThread.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include<iostream>
#include<vector>
#include<map>
#include<string> 
#include<thread>
using namespace std;
class CObject
{
    
    
	int& m_obj;
public:
	CObject(int& i) :m_obj(i) {
    
    
		cout << "ctor" << endl;
	}
	CObject(const CObject& m) :m_obj(m.m_obj) {
    
    
		cout << "copy ctor" << endl;
	}
	~CObject(){
    
    
		cout << "dtor" << endl;
	}
	void operator ()() {
    
     // 不带参数
		cout << "线程开始运行1" << endl;
		cout << "线程开始运行2" << endl;
		cout << "线程开始运行3" << endl;
		cout << "线程开始运行4" << endl;
		cout << "线程开始运行5" << endl;
	}
};
int main()
{
    
    
	int i = 6;
	CObject obj(i);
	std::thread my2Obj(obj); // 主线程阻塞在这,并等待myPrint()执行完
	if (my2Obj.joinable()){
    
    
		my2Obj.detach();
	}
	cout << "see you " << endl;
	
    return 0;
}

The destructor of the child thread is executed in the background, so the output dtor is the main thread. The result of using join() is:

3. Create threads through lambda expressions

int main()
{
    
    
	auto myLamThread = [] {
    
    
		cout << "线程开始运行" << endl;
		cout << "线程结束运行" << endl;
	};
	thread cthread(myLamThread);
	cthread.join();
	std::cout << "see you " << endl;
	
    return 0;
}

It is better to apply what you have learned, and there may be shortcomings in the above, welcome to point out the discussion.

Guess you like

Origin blog.csdn.net/weixin_52622200/article/details/110440419