0%

1. 控制线程数

  • Method 1: Use the environment variable TBB_NUM_THREADS for the gloabl setting.
1
export TBB_NUM_THREADS=4

TODO: It doesn’t seem to work!

  • Method 2: Use tbb::task_arena or tbb::task_scheduler_init (Deprecated).

TBB will use this setting locally within the scope of the tbb::task_arena.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <tbb/pipeline.h>
// Deprecated:
// #include <tbb/task_scheduler_init.h>
#include <tbb/task_arena.h>

// Define your pipeline body
class MyPipeline {
public:
void operator() (tbb::flow_control& fc) const {
// Your pipeline logic here
// ...
// Inform the pipeline that there is no more data
fc.stop();
}
};

int main() {
// Deprecated: tbb::task_scheduler_init init(1);
tbb::task_arena arena(4); // 4 threads
// Do some tasks:
tbb::parallel_pipeline(/* max_number_of_live_tokens */ 4, MyPipeline); // FIXME: 似乎需要放入 arena 的 execute 函数中

return 0;
}

2. parallel_for

API: parallel_for

  1. my_parallel_for 模拟 parallel_for 的实现:
my_parallel_for.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <tbb/tbb.h>
#include <vector>
#include <iostream>

// 模拟 parallel_for 的内部实现
void my_parallel_for(const tbb::blocked_range<size_t>& range, const std::function<void(const tbb::blocked_range<size_t>&)>& body) {
if (range.is_divisible()) {
// 分割范围
tbb::blocked_range<size_t> left(range.begin(), range.begin() + (range.end() - range.begin()) / 2);
tbb::blocked_range<size_t> right(left.end(), range.end());

// 递归调用
tbb::parallel_invoke(
[&] { my_parallel_for(left, body); },
[&] { my_parallel_for(right, body); }
);
} else {
// 处理当前范围
body(range);
}
}

int main() {
std::vector<int> data(100);
for (int i = 0; i < 100; ++i) {
data[i] = i;
}

// 使用自定义的 parallel_for 进行并行处理
my_parallel_for(tbb::blocked_range<size_t>(0, data.size()), [&](const tbb::blocked_range<size_t>& r) {
for (size_t i = r.begin(); i != r.end(); ++i) {
data[i] *= 2; // 示例操作:将每个元素乘以2
}
});

// 输出结果
for (const auto& val : data) {
std::cout << val << " ";
}
std::cout << std::endl;

return 0;
}
  1. 发出任务的线程也会成为工作线程之一,并参与任务的执行,测试代码如下:
test_parallel_for.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <tbb/tbb.h>

#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
using namespace std;
using namespace tbb;

static std::atomic<int> total_blocks(0); // Atomic counter to track the number of tasks processed
static std::atomic<int> total_blocks2(0); // Atomic counter to track the number of tasks processed

// Function to process each data element
void process_data(int i, std::mutex& mtx) {
// std::this_thread::sleep_for(std::chrono::milliseconds(1)); // Simulate some processing time
for (int i = 0; i < 100; ++i)
;
}

int main(int argc, char* argv[]) {
if (argc < 3) {
std::cerr << "Usage: " << argv[0] << " <number_of_elements>"
<< "<grain_size>" << std::endl;
return 1;
}

int num_elements = std::stoi(argv[1]);
int grain_size = std::stoi(argv[2]);

std::mutex mtx;
std::vector<int> data(num_elements);
for (int i = 0; i < num_elements; ++i) {
data[i] = i;
}

// {
// std::lock_guard<std::mutex> lock(mtx);
// std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;
// }

tbb::concurrent_unordered_map<std::thread::id, tbb::concurrent_vector<int>> thread_task_counts; // To store task counts for each thread
tbb::concurrent_unordered_map<std::thread::id, tbb::concurrent_vector<int>> thread_task_counts2; // To store task counts for each thread

tbb::parallel_for(0, static_cast<int>((data.size() + grain_size - 1) / grain_size), [&](int i) {
total_blocks++;
int cnt = 0; // Thread-local variable to avoid data
for (int j = i * grain_size; j < std::min(static_cast<int>(data.size()), (i + 1) * grain_size); ++j) {
process_data(i, mtx);
++cnt;
}
thread_task_counts[std::this_thread::get_id()].push_back(cnt);
});

tbb::parallel_for(blocked_range<int>(0u, data.size(), grain_size), [&](const blocked_range<int>& r) {
total_blocks2++;
int cnt = 0; // Thread-local variable to avoid data
for (int i = r.begin(); i < r.end(); ++i) {
process_data(i, mtx);
++cnt;
}
thread_task_counts2[std::this_thread::get_id()].push_back(cnt);
});

std::cout << "Total blocks processed: " << total_blocks.load() << std::endl;
for (const auto& pair : thread_task_counts) {
std::cout << "Thread " << pair.first << " processed: ";
for (const auto& task_count : pair.second)
std::cout << task_count << ", ";
std::cout << std::endl;
}

std::cout << "Total blocks2 processed: " << total_blocks2.load() << std::endl;
for (const auto& pair : thread_task_counts2) {
std::cout << "Thread " << pair.first << " processed: ";
for (const auto& task_count : pair.second)
std::cout << task_count << ", ";
std::cout << std::endl;
}

return 0;
}

测试结果:

1
2
3
4
5
6
7
$ ./test_parallel_for 
Main thread ID: 140220582070080
Processing data: 2 on thread 140220582070080
Processing data: 6 on thread 140220557755968
Processing data: 4 on thread 140220574795328
Processing data: 8 on thread 140220566275648
Processing data: 10 on thread 140220562015808

可见,data 2 是由主线程处理的。也就是说,parallel_for 虽然被称为 a blocking parallel construt,但线程等待所有任务完成期间是非阻塞的,它还可以充当工作线程执行任务池中的任务。

代码模拟 parallel_forwait

my_task_scheduler.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <iostream>
#include <vector>
#include <thread>
#include <functional>
#include <condition_variable>
#include <queue>

class TaskScheduler {
public:
TaskScheduler(size_t numThreads);
~TaskScheduler();
void enqueue(std::function<void()> task);
void wait();

private:
std::vector<std::thread> workers;
std::queue<std::function<void()>> tasks;
std::mutex queueMutex;
std::condition_variable condition;
std::condition_variable finished;
bool stop;
size_t activeTasks;

void workerThread();
void executeTask();
};

TaskScheduler::TaskScheduler(size_t numThreads) : stop(false), activeTasks(0) {
for (size_t i = 0; i < numThreads; ++i) {
workers.emplace_back(&TaskScheduler::workerThread, this);
}
}

TaskScheduler::~TaskScheduler() {
{
std::unique_lock<std::mutex> lock(queueMutex);
stop = true;
}
condition.notify_all();
for (std::thread &worker : workers) {
worker.join();
}
}

void TaskScheduler::enqueue(std::function<void()> task) {
{
std::unique_lock<std::mutex> lock(queueMutex);
tasks.push(std::move(task));
}
condition.notify_one();
}

void TaskScheduler::wait() {
std::unique_lock<std::mutex> lock(queueMutex);
while (!tasks.empty() || activeTasks > 0) {
// 如果还有任务,执行一个任务,避免当前线程被阻塞
if (!tasks.empty()) {
executeTask();
} else {
finished.wait(lock);
}
}
}

void TaskScheduler::workerThread() {
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queueMutex);
condition.wait(lock, [this] { return stop || !tasks.empty(); });
if (stop && tasks.empty()) return;
task = std::move(tasks.front());
tasks.pop();
++activeTasks;
}
task();
{
std::unique_lock<std::mutex> lock(queueMutex);
--activeTasks;
if (tasks.empty() && activeTasks == 0) {
finished.notify_all();
}
}
}
}

void TaskScheduler::executeTask() {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queueMutex);
if (tasks.empty()) return;
task = std::move(tasks.front());
tasks.pop();
++activeTasks;
}
task();
{
std::unique_lock<std::mutex> lock(queueMutex);
--activeTasks;
if (tasks.empty() && activeTasks == 0) {
finished.notify_all();
}
}
}

void parallel_for(int start, int end, std::function<void(int)> func) {
static TaskScheduler scheduler(std::thread::hardware_concurrency());
for (int i = start; i < end; ++i) {
scheduler.enqueue([i, &func] { func(i); });
}
scheduler.wait();
}

int main() {
const int N1 = 100;
const int N2 = 100;

// The first parallel loop.
parallel_for(0, N1, [&](int i) {
// The second parallel loop.
parallel_for(0, N2, [&](int j) {
// Some work
});
// 线程发出 parallel_for 之后,需要等待内部所有 parallel loop 的任务完成
// 在此期间允许继续拿取外部的 parallel loop 的任务执行
});

return 0;
}

3. TBB线程池

TBB似乎总是使用同一个全局线程池。测试代码如下:

tbb_thread_pool.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <tbb/tbb.h>
#include <unistd.h>

#include <iostream>
#include <mutex>
#include <thread>
#include <vector>

using namespace std;

std::mutex mtx;

void task_group_function() {
tbb::task_group tg;
int max_concurrency = tbb::this_task_arena::max_concurrency();
{
std::lock_guard<std::mutex> lock(mtx);
cout << "Task group max concurrency: " << max_concurrency << endl;
}
for (int i = 0; i < 16; ++i) {
tg.run([i] {
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Task group thread " << std::this_thread::get_id() << " is running." << std::endl;
}
sleep(1);
});
}
tg.wait();
}

void task_arena_function() {
tbb::task_arena arena(4);
int max_concurrency = arena.max_concurrency();
{
std::lock_guard<std::mutex> lock(mtx);
cout << "Task arena max concurrency: " << max_concurrency << endl;
}
arena.execute([max_concurrency] {
tbb::parallel_for(0, 16, [](int i) {
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Task arena thread " << std::this_thread::get_id() << " is running." << std::endl;
}
sleep(2);
});
});
}

int main() {
// 获取默认task_arena的最大并发线程数
int arena_max_concurrency = tbb::this_task_arena::max_concurrency();
std::cout << "Default task_arena max concurrency: " << arena_max_concurrency << std::endl;

// 创建两个线程
std::thread tg_thread(task_group_function);
std::thread ta_thread(task_arena_function);

// 等待两个线程完成
tg_thread.join();
ta_thread.join();

return 0;
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ mkdir build && cd build && cmake .. && make
$ ./tbb_thread_pool > result.txt
$ cat result.txt | grep running | sort | uniq
Task arena thread 140667163379264 is running.
Task arena thread 140667167639104 is running.
Task arena thread 140667184678464 is running.
Task arena thread 140667201848896 is running.
Task group thread 140667167639104 is running.
Task group thread 140667171898944 is running.
Task group thread 140667176158784 is running.
Task group thread 140667180418624 is running.
Task group thread 140667188938304 is running.
Task group thread 140667210303040 is running.

从这两行日志可以看出,arena 和 group 重用了同一个线程 ID ,说明它们同属于同一个全局线程池。

1
2
Task arena thread 140667167639104 is running.
Task group thread 140667167639104 is running.

进一步,我们发现全局线程池中的线程总数是自适应的,比如本例就是 10 个,既不是 task_group8 个,
也不是 task_arena4 个:

TODO

1
2
$ cat result.txt | grep running | sort | uniq | wc -l
10

4. 任务调度器(Task Scheduler)

The Task Scheduler

4.1. 基于任务编程(Task-Based Programming)

当追求性能时,推荐以逻辑任务(logical tasks)而不是线程(threads)来编程,有以下原因:

  • 将并行性与可用资源匹配
  • 更快的任务启动和关闭
  • 更有效的评估顺序
  • 改进负载均衡
  • 更高层的思考

TODO

4.2. 任务调度器(Task Scheduler)如何工作

How Task Scheduler Works

4.2.1. 深度优先(depth-first)

每个线程都有自己的双端队列,头部称为 top (也称顶部),尾部称为 bottom (也称底部)。
队列的底部是队列的最深处(最末处),底部任务是最新的,顶部任务是最旧的。

深度优先有以下好处:

  • 热点缓存命中:最新的任务的缓存是最热的,所以优先执行新任务。
  • 最小化空间:广度优先会同时创建指数级数量的共存节点,而深度优先虽然也会创建相同数量的节点,但是只有线性数目的节点会同时共存,因为它创建了其他就绪任务的栈。

生产:当线程产生一个任务时,将其放置到线程自身所有的 deque 的尾部。

消费:当线程执行任务时,根据以下规则顺序选取一个任务:

  • 规则1:获取上一个任务返回的任务,如果有;
  • 规则2:从线程自己所有的 deque 尾部选取一个任务(即深度优先),如果有;
  • 规则3:随机选择一个其他线程的 deque ,从其头部窃取一个任务(即广度优先)。如果被选 deque 为空,则重复本条规则直至成功。

规则1 被称为“任务调度绕行(Task Scheduler Bypass)”。

规则2 是深度优先,这使得当前线程得以不断执行最新的任务直至其完成所有工作。

规则3 是临时的广度优先,它将潜在的并行转化为实际的并行。

4.2.2. 任务调度绕行(Task Scheduler Bypass)技术

一个任务从产生到被执行涉及以下步骤:

  • 将新任务加入线程的 deque 。
  • 执行当前任务直至完成。
  • 从线程 deque 获取一个任务执行,除非该任务被其他线程窃取走了。

其中,步骤1 和 步骤3 会引入不必要的 deque 操作,甚至更糟的是,允许窃取会损害局部性而不会增加显著的并行性。
任务调度器绕行技术可以直接指向下一个要被执行的任务,而不是生产该任务,从而避免了上述问题。
因为根据“规则1”,上一个任务产生的新任务会称为第一个备选任务。
此外,该技术几乎保证了该新任务被当前线程执行,而不是其他线程。

注意:当前唯一能使用该优化技术的是使用 tbb::task_group

4.3. 指导任务调度器的执行(Guiding Task Scheduler Execution)

Guiding Task Scheduler Execution

默认情况下,任务计划程序会尝试使用所有可用的计算资源。在某些情况下,您可能希望将任务计划程序配置为仅使用其中的一些资源。

注意:指导任务调度程序的执行可能会导致可组合性问题。

TBB 提供 task_arena 接口,通过以下方式指导任务在 arena (竞技场)内被执行:

  • 设置首选计算单元;
  • 限制部分计算单元。

4.4. 工作隔离(Work Isolation)

Work Isolation

work_isolation_eg1.cppview raw
1
2
3
4
5
// The first parallel loop.
oneapi::tbb::parallel_for( 0, N1, []( int i ) {
// The second parallel loop.
oneapi::tbb::parallel_for( 0, N2, []( int j ) { /* Some work */ } );
} );

如果当前线程被 parallel_for “阻塞”(不是真正的阻塞,只能称为 a blocking parallel construct),那么该线程被允许拿取第一个循环的任务来执行。这会导致即使是同一个线程内,也可出现乱序执行的情况。在大多数情况下,这没有什么危害。

但是少数情况可能出现错误,例如一个 thread-local 变量可能会在嵌套并行构造之外意外被更改:

work_isolation_eg2.cppview raw
1
2
3
4
5
6
7
8
9
oneapi::tbb::enumerable_thread_specific<int> ets;
oneapi::tbb::parallel_for( 0, N1, [&ets]( int i ) {
// Set a thread specific value
ets.local() = i;
oneapi::tbb::parallel_for( 0, N2, []( int j ) { /* Some work */ } );
// While executing the above parallel_for, the thread might have run iterations
// of the outer parallel_for, and so might have changed the thread specific value.
assert( ets.local()==i ); // The assertion may fail!
} );

在其它场景下,这种行为可能会导致死锁或其他问题。在这些情况下,需要更有力地保证线程内的执行次序。为此,TBB 提供了一些隔离并行构造的执行的方法,以使其任务不会干扰其他同时运行的任务。

其中一种方法是在单独的 task_arena 中执行内层循环:

work_isolation_eg3.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
oneapi::tbb::enumerable_thread_specific<int> ets;
oneapi::tbb::task_arena nested;
oneapi::tbb::parallel_for( 0, N1, [&]( int i ) {
// Set a thread specific value
ets.local() = i;
nested.execute( []{
// Run the inner parallel_for in a separate arena to prevent the thread
// from taking tasks of the outer parallel_for.
oneapi::tbb::parallel_for( 0, N2, []( int j ) { /* Some work */ } );
} );
assert( ets.local()==i ); // Valid assertion
} );

然而,使用单独的 arena 进行工作隔离并不总是方便的,并且可能会产生明显的开销。为了解决这些缺点,TBB 提供 this_task_arena::isolate 函数,通过限制调用线程仅处理在函数对象范围内(也称为隔离区域)安排的任务,来隔离地运行一个用户提供的函数对象。

当一个线程进入一个任务等待调用或(等待)在一个隔离区域内的阻塞并行结构时,该线程只能执行在该隔离区域内生成的任务及其由其他线程生成的子任务(换句话说,即使子任务是由其他线程生成的,只要属于当前隔离区域,当前线程也可以执行这些任务)。线程被禁止执行任何外层任务或属于其他隔离区域的任务。

下面的示例展示了 this_task_arena::isolate 的使用,以保证在嵌套的并行结构调用时, thread-local 变量不会被意外修改:

work_isolation_eg4.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "oneapi/tbb/task_arena.h"
#include "oneapi/tbb/parallel_for.h"
#include "oneapi/tbb/enumerable_thread_specific.h"
#include <cassert>


int main() {
const int N1 = 1000, N2 = 1000;
oneapi::tbb::enumerable_thread_specific<int> ets;
oneapi::tbb::parallel_for( 0, N1, [&ets]( int i ) {
// Set a thread specific value
ets.local() = i;
// Run the second parallel loop in an isolated region to prevent the current thread
// from taking tasks related to the outer parallel loop.
oneapi::tbb::this_task_arena::isolate( []{
oneapi::tbb::parallel_for( 0, N2, []( int j ) { /* Some work */ } );
} );
assert( ets.local()==i ); // Valid assertion
} );
return 0;
}

补充:让我们通过一个简单的例子来说明隔离区域内其他线程如何生成子任务,并且这些子任务可以由当前线程执行。

假设我们有一个隔离区域,其中有两个线程:线程A和线程B。我们在这个隔离区域内生成了一些任务,并且这些任务可能会生成子任务。

work_isolation_eg5.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <tbb/tbb.h>
#include <iostream>

void taskA() {
std::cout << "Task A executed by thread " << tbb::this_task_arena::current_thread_index() << std::endl;
tbb::parallel_invoke(
{
std::cout << "Subtask A1 executed by thread " << tbb::this_task_arena::current_thread_index() << std::endl;
},
{
std::cout << "Subtask A2 executed by thread " << tbb::this_task_arena::current_thread_index() << std::endl;
}
);
}

void taskB() {
std::cout << "Task B executed by thread " << tbb::this_task_arena::current_thread_index() << std::endl;
tbb::parallel_invoke(
{
std::cout << "Subtask B1 executed by thread " << tbb::this_task_arena::current_thread_index() << std::endl;
},
{
std::cout << "Subtask B2 executed by thread " << tbb::this_task_arena::current_thread_index() << std::endl;
}
);
}

int main() {
tbb::task_arena arena;
arena.execute([&] {
tbb::this_task_arena::isolate([&] {
tbb::parallel_invoke(taskA, taskB);
});
});
return 0;
}

在这个例子中:

taskA 和 taskB 是在隔离区域内生成的任务。
taskA 生成了两个子任务 Subtask A1 和 Subtask A2。
taskB 生成了两个子任务 Subtask B1 和 Subtask B2。
假设线程A执行了 taskA,线程B执行了 taskB。在隔离区域内,线程A和线程B可以执行彼此生成的子任务。例如,线程A可以执行 Subtask B1 或 Subtask B2,而线程B可以执行 Subtask A1 或 Subtask A2,只要这些子任务属于同一个隔离区域。

5. 推荐阅读

5.1. 书籍

  1. Intel Building Blocks 编程指南. James Reinders.
  2. Patterns for Parallel Pragramming. Timothy Mattson 等.
  3. 设计模式:Design Patterns of Reusable Object-Oriented Software (Addison Wesley). Gamma, Helm, Johnson 和 Vlissides.

gcc

gcc是一个编译套件,包含c、c++、Fortran语言的编译器。

glibc

glibc是一个library,为C程序提供基础公共功能,包括系统调用、数学函数和其他核心组件。
Linux平台和vscode似乎都依赖glibc,如果擅自将LD_LIBRARY_PATH更改为其他版本的glibc路径,则bash会直接crash。

glibc包含以下bin和lib:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ cd glibc-v2.34/Linux/RHEL7.0-2017-x86_64/bin && ls
catchsegv getconf iconv locale makedb pcprofiledump sotruss tzselect zdump
gencat getent ldd localedef mtrace pldd sprof xtrace

# 进入其他版本的glibc/lib目录执行ls命令会报错,大概原因可能是因为当前路径的glibc的lib和系统的lib冲突。
$ cd ../lib && ls
ls: relocation error: ./libc.so.6: symbol __tunable_get_val, version GLIBC_PRIVATE not defined in file ld-linux-x86-64.so.2 with link time reference

$ cd .. && ls lib
Mcrt1.o libanl.so.1 libm.so libnss_hesiod.so.2
Scrt1.o libc.a libm.so.6 libpcprofile.so
audit libc.so libmcheck.a libpthread.a
crt1.o libc.so.6 libmemusage.so libpthread.so.0
crti.o libc_malloc_debug.so libmvec.a libresolv.a
crtn.o libc_malloc_debug.so.0 libmvec.so libresolv.so
gconv libc_nonshared.a libmvec.so.1 libresolv.so.2
gcrt1.o libcrypt.a libnsl.so.1 librt.a
ld-linux-x86-64.so.2 libcrypt.so libnss_compat.so librt.so.1
libBrokenLocale.a libcrypt.so.1 libnss_compat.so.2 libthread_db.so
libBrokenLocale.so libdl.a libnss_db.so libthread_db.so.1
libBrokenLocale.so.1 libdl.so.2 libnss_db.so.2 libutil.a
libSegFault.so libg.a libnss_dns.so.2 libutil.so.1
libanl.a libm-2.34.a libnss_files.so.2
libanl.so libm.a libnss_hesiod.so

查看glibc的版本:

1
2
# 从上可知,ldd是glibc的核心组件之一
$ ldd --version

寻找libc.so的路径:

1
2
3
4
5
6
7
8
$ locate libc.so
/usr/lib/x86_64-linux-gnu/libc.so
/usr/lib/x86_64-linux-gnu/libc.so.6
$ locate libstdc++.so
/usr/lib/gcc/x86_64-linux-gnu/11/libstdc++.so
/usr/lib/x86_64-linux-gnu/libstdc++.so.6
/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30
/usr/share/gdb/auto-load/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30-gdb.py

安装glibc:

Ubuntu平台

1
sudo apt-get install lib6

RedHat平台

1
sudo yum install glibc

检查GNC C++ Library (libstdc++)的版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ strings /usr/lib/libstdc++.so.* | grep LIBCXX
[sjcvl-zhigaoz ] /lan/cva_rel/vxe_main/24.02.650.d000/tools.lnx86/lib/64bit % strings /usr/lib/libstdc++.so.* | grep LIBCXX
GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
...
GLIBCXX_3.4.19
GLIBCXX_DEBUG_MESSAGE_LENGTH

$ strings /usr/lib/libc.so.* | grep GLIBC
GLIBC_2.0
GLIBC_2.1
GLIBC_2.1.1
...
GLIBC_2.17
GLIBC_PRIVATE

如果你有一个使用了libstdc++的特定的binary或application,可以用下面的命令来检查其版本:

1
$ ldd <your_binary_or_application> | grep libstdc++

使用vscode的“Remote SSH”工具试图连接到Linux时,可能会报错如下:

Warning: Missing GLIBCXX >= 3.4.25! from /usr/lib64/libstdc++.so.6.0.19
Warning: Missing GLIBC >= 2.28! from /usr/lib64/libc-2.17.so
Error: Missing required dependencies. Please refer to our FAQ https://aka.ms/vscode-remote/faq/old-linux for additional information.

这是因为Linux系统上的glibc版本中不包含GLIBCXX_3.4.25及以上的版本。此时需要降级vscode(建议做法)或升级glibc(似乎很难)。

times

  1. bash built-in
1
times
  1. function
1
2
3
#include <sys/times.h>

clock_t times(struct tms *buf);

malloc/free

See this example

1
char ** backtrace_symbols (void *const *buffer, int size) 

The return value of backtrace_symbols is a pointer obtained via the malloc function, and it is the responsibility of the caller to free that pointer. Note that only the return value need be freed, not the individual strings.

Question: Why does it say “only the return value need be freed, not the individual strings”?

Let us observe the defintion of the malloc/free functions first:

1
2
void *malloc( size_t size );
void free( void *ptr );

free takes a void* pointer to deallocate the memory, it doesn’t care what type it is, even if it is a multi-level pointer. It means that malloc has stored the memory size in some place and free will find it beforing deallocate the memory.

Let us return the question. The memory pointer returned by backtrace_symbols is the char** type, it must be a whole block contigunous memory using malloc and might be enforced to be transformed as char** pointer when returing. So when we free the memory block, the Linux kernel find its actual memory size and deallocate it.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
char** strings = (char**)malloc(3 * sizeof(char*) + 3 * 50); // assuming a maximum 50 characters per sentence
char* block = (char*)(strings + 3);
char* s1 = strcpy(block, "The first sentence"); block += strlen(s1) + 1;
char* s2 = strcpy(block, "The second sentence"); block += strlen(s2) + 1;
char* s3 = strcpy(block, "The third sentence");
strings[0] = s1;
strings[1] = s2;
strings[2] = s3;
for(int i = 0; i < 3; ++i) {
printf("%s\n", strings[i]);
}
free(strings); // deallocate all memory at once

return 0;
}

More elegant but less economical code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
char** strings = (char**)malloc(3 * sizeof(char*) + 3 * 50);
char* block = (char*)(strings + 3);
for(int i = 0; i < 3; ++i) {
strings[i] = block + i * 50; // Assuming a maximum of 50 characters per sentence
}
strcpy(strings[0], "The first sentence");
strcpy(strings[1], "The second sentence");
strcpy(strings[2], "The third sentence");

for(int i = 0; i < 3; ++i) {
printf("%s\n", strings[i]);
}

free(strings); // deallocate all memory at once

return 0;
}

Reference

shuf

cut

tr

lp

sort

Options:

-t, --field-separator=SEP
    use SEP instead of non-blank to blank transition

-k, --key=POS1[,POS2]
    start a key at POS1 (origin 1), end it at POS2 (default end of line)

-h, --human-numeric-sort
    compare human readable numbers (e.g., 2K 1G)

-n, --numeric-sort
    compare according to string numerical value

nproc

print the number of processing units avaiable.

od / xxd / hexdump

read the binary file.

Notes: byte order

1
2
3
4
5
$ echo -n "ABCD" | xxd
00000000: 4142 4344 ABCD
$ echo -n "ABCD" | hexdump
0000000 4241 4443
0000004

Reference

comm / diff / tkdiff / cmp

Can be used to compare binary or non-binary files.

comm

compare two sorted files line by line.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ cat file1.txt 
apple
banana
cherry

$ cat file2.txt
banana
cherry
date
erase

$ comm file1.txt file2.txt
apple
banana
cherry
date
erase

The file must be sorted before using the comm command. Otherwise it will complain that:

comm: file 1 is not in sorted order

and cannot work correctly. For example,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ cat file1.txt 
apple
cherry
banana

$ cat file2.txt
banana
cherry
date
erase

$ comm file1.txt file2.txt
apple
banana
cherry
comm: file 1 is not in sorted order
banana
date
erase
comm: input is not in sorted order

diff

Syntax:

diff -u file1 file2

Options:

-e, --ed
    output an ed script

-u, -U NUM, --unified[=NUM]
    output NUM (default 3) lines of unified context
    (that is, print NUM lines before and after the difference line)

tkdiff

Use a GUI to display the differences.

cmp

Prints less information comparing to diff.

Syntax:

cmp file1 file2

ed/vim/sed/awk

列表初始化

struct/union/array默认支持列表初始化。

Struct and union initialization
Array initialization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <bits/stdc++.h>
// #include <initializer_list>
using namespace std;

class A {
public:
int x, y, z; // 注意:数据成员必须是public的。
void print() {
cout << x << " " << y << " " << z << endl;
}
};

class B {
public:
vector<int> vec_;
int x_;
void print() {
cout << "vec_={ ";
for (int x : vec_) {
cout << x << " ";
}
cout << "}, x_=" << x_ << endl;
}
};

class C {
public:
vector<int> vec_;
void print() {
cout << "vec_={ ";
for (int x : vec_) {
cout << x << " ";
}
cout << "}" << endl;
}
};

int main() {
// C++会构造一个列表初始化的默认构造函数,
// 以下(1)和(2)都是调用这个默认构造函数。
A a1{1,2,3}; // (1) 列表初始化
A a2({4,5,6}); // (2) 同(1)
a1.print();
a2.print();

B b1{{1,2,3}, 4}; // 内部的"{1,2,3}"用于构造vec_,"4"用于初始化x_
b1.print();

// C C1{1,2,3}; // (1) 这里会报错"error: too many initializers for ‘C’",
// // 因为C只有一个数据成员vec_,这里却传入了3个参数
C c2{{1,2,3}}; // (2) 其中,内部的"{1,2,3}"用于构造vec_,外层的"{}"用于对c2本身进行构造
c2.print();

return 0;
}

std::initializer_list

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <bits/stdc++.h>
#include <initializer_list>
using namespace std;

struct A {
int x, y, z;

A(initializer_list<int> il) {
initializer_list<int>::iterator it = il.begin();
x = *it++;
y = *it++;
z = *it++;
}

void print() {
cout << x << " " << y << " " << z << endl;
}
};

struct B {
vector<int> vec;

B(initializer_list<int> il) {
vec = il; // 用initializer_list初始化vector
}

void print() {
cout << "{ ";
for (int x : vec) {
cout << x << " ";
}
cout << "}" << endl;
}
};

int main() {
A a{1,2,3};
a.print();

B b{4,5,6};
b.print();

return 0;
}

中括号

  1. [ ]test是bash的内部命令,[[ ]]是shell的条件判断关键字。

    1
    2
    3
    4
    5
    6
    $ type [
    [ is a shell builtin
    $ type test
    test is a shell builtin
    $ type [[
    [[ is a shell keyword
  2. [ ]test是等价的,用于评估条件表达式。可以使用man [help [查阅帮助文档。

    1
    2
    3
    4
    5
    6
    $ help [
    [: [ arg... ]
    Evaluate conditional expression.

    This is a synonym for the "test" builtin, but the last argument must
    be a literal `]', to match the opening `['.
  3. [[ ]]关键字可以屏蔽shell特殊符号,比如&&||><可以被认为是条件判断符而不是重定向符。

  4. [ ]中使用-a-o表示逻辑与和逻辑或,[[ ]]中则使用&&||

小括号

  1. $()用于命令替换。
  2. 双小括号(( )):在比较过程中使用高级数学表达式。

大括号

请阅读:All about {Curly Braces} in Bash

  1. ${}用于引用变量。

    $var相比,${var}是一种消除歧义的措施,比如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ var=abc
    $ vartest=ABC
    # $var引用变量'var'
    $ echo $var
    abc
    # 引用变量'vartest'
    $ echo $vartest
    ABC
    # 引用变量'var'并在其后加上'test'字符
    $ echo ${var}test
    abctest
  2. {}表示分组。

Reference

regexp

ERegExp

Wildcard/Glob

man 7 glob

glob - globbing pathnames. glob is a shell built-in.

主要用于匹配带有通配符的文件路径。其匹配字符串的能力比正则表达式弱。

它最初是贝尔实验室 Unix 系统上的一个名叫 glob 的命令(glob 是 global 的缩写),用于展开命令行中的通配符。后来系统提供了该功能的 C 语言库函数glob(),知名的 shell 解释器就使用了该接口,shell 脚本和命令行中使用的 glob 模式匹配功能便源自于此。——见博客

Wildcards

{}严格来讲不属于glob的范畴,其在shell表示一个分组,见:All about {Curly Braces} in Bash

sed

awk

awk Command

格式

1
awk -F' *|:' '/LISTEN/{print $2}'

其中,-F表示分隔符;
*|:是一个正则表达式,表示以”一个或多个空格”或”:”作为分隔符;
再其后的//中是另一个正则表达式,用于匹配文本;
{}中是action。

条件判断

if-else in awk
use AND and OR in an awk program

1
awk '{if ($1 > 49151 && $1 < 65536) {print $1} }'

等价于

1
awk '$1 > 49151 && $1 < 65536'

BEGIN/END

In AWK, BEGIN and END are special patterns that allow you to execute code before processing the input (BEGIN) or after processing all the input (END).

  • The BEGIN block is executed once at the beginning of the AWK program and it is typically used for initializing variables or performing setup tasks.
  • The END block is executed once after processing all input, and it is commonly used for final caclucations, summaries, or printing results.

Special symbols

  • $ 用于引用field,例如$1代表第一个field(典型来说是第一列)。
  • NF 表示number of filed,假设一共有7列,那么$NF$7等价。

grep

Example

  1. 找出一个未使用的port
1
2
3
4
5
6
7
# "$$"是为了转义"$"
max_port=$(shell netstat -antulpen 2> /dev/null \
| awk -F' *' '/^(tcp|udp)/{print $$4}' | cut -d: -f 2 \
| egrep "\w" | sort | tail -1)
#$(warning ${max_port})
port=$(shell expr $(max_port) + 1)
#$(warning ${port})
1
2
3
4
5
6
# 从1025开始找出已经存在的端口,如果相邻端口的gap大于1,则返回“当前端口号+1”
netstat -ant | awk '{print $4}' \
| awk -F: '{if ($NF ~ /^[0-9]+$/ && $NF > 1024) {print $NF}}' \
| awk 'BEGIN {prev = 1024}
{if ($1 - prev > 1) { port = prev + 1; exit} else { prev = $1}}
END { if (port=="") {print prev + 1} else {print port}}'
1
2
3
4
5
6
7
8
9
10
11
12
#这不是正则表达式
#以0端口为参数创建一个socket,则系统会自动选择一个未使用的端口号

#one-line mode:
#python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()'
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 0))
addr = s.getsockname()
print(addr[1])
s.close()

Video

视频:链接

影片名:Midsomer Murders, S01:E01, The Killings at Badger’s Drift

S01:E01 - Season 01 : Episode 01,第1季第1集。episode,插曲(某事件;某事发生的短暂时间);剧集(一般一周更新放映一次)。

midsomer - midsummer的过时写法。本片中是一个虚构的英格兰县,影片开头有一个路牌,写着:“Badger’s Drift, Midsomer’s best kept village”,意思大概是,Badger’s Drift是Midsomer保存最好的村庄。

开幕介绍

Screenplay by Anthony Horowitz - Screenplay 剧本。

From the novel by Caroline Graham

Starring - 主演

Directed by - 导演是

caption - 字幕。

subtitle - 字幕。

第一幕 Emily之死

村落小路上

-[Doctor] Hello, Missis Simpson. Have a very good afternoon.

bright playful music - 明快俏皮的音乐。

Daily Mirror, forward with the people. 这是一块招牌上的字样。《每日镜报》的口号是“与人民同行”,The Sun’s slogan was ‘Forward with the People’, which had been adopted by the Mirror in 1945 and only recently dropped. - 参见谷歌快照《An Introduction to the Daily Mirror》。hayday好天气,全盛时期。hay干草。

-[Lucy] Ah, sneaking off, aren’t you, Emily? 偷偷溜走,不是吗?

-[Emily] I wouldn’t call it sneaking, Lucy. Anyway, who’s talking? You’ve been out all day! 我不会称它为溜。不管怎样,是谁在说话?你自己已经出去一整天了!

-I’m not gonna tell you where. 我不会告诉你我去了哪里。

-You didn’t find it? 你没有找到?

-No. 没有。

-You’ll be buying me tea this year, my dear. You wait and see! 今年你会给我买茶,你等着看!

-Chance would be a fine thing! 有机会(让我给你买茶)就好了!

pros and cons - 优点和缺点

树林

birds chirp - 鸟儿叽叽喳喳。

Spurred coral root - 刺珊瑚根。spur马刺。”It’s an orchid(兰花), not a flower.”

padlock clicks - 挂锁咔咔声。

camera clicks - 相机咔咔声。

man moans - 男人呻吟。

man pants - 男人喘息。pant喘气。

bird flaps - 鸟儿拍飞。

Emily shrieks - Emily尖叫。

Emily回家路上

brakes screech - 刹车声。brake刹车,screech发出尖叫、噪声。

Emily家

slow sinister music - sinister险恶的。

bees buzz - 蜜蜂嗡嗡。

beehive cottage - 蜂巢小屋。beehive /ˈbiː.haɪv/ 蜂窝;cottage /ˈkɑː.t̬ɪdʒ/ /ˈkɒt.ɪdʒ/小屋。

cat meows - meow /ˌmiˈaʊ/ 喵

Come on, out you go - 来,你出去。

door thuds - 门砰的一声。thud /θʌd/ 撞击声,砰。

dial up phone rattles - 拨号嘎嘎声。rattle 拨浪鼓;嘎嘎声。

door rattles.

bangs. - to (cause something to) make a sudden very loud noise or noises.

birds squawk - 鸟叫(不好的声音)。squawk - (of a bird) to make an unpleasantly loud, sharp noise.

door knocks - 敲门声。

door knob screeches - 门把手尖叫(声)。

intense sinister music - 激烈险恶的音乐。

dark dreamy music - 黑暗梦幻的音乐。

第二幕 初步调查

-This is it, here, Sir.

-Really, Troy? I’d never have guessed.

crowd chatters - 人群闲聊。

We only ever meet when there’s a corpse. - 我们只有在有尸体的时候会见面。corpose - 尸体。ever - at any time: Nothing ever happened in this evening. Have you ever gone to London?

broken neck - 脖子断了。

scuff marks on the carpet - 地毯上有磨损痕迹。scuff vt. 磨损,擦伤。

a blow to the back of the neck and then dragged over here - 颈后遭到一击,然后被拖到这里。

spinster - 老处女。

The old girl who lives opposite - 住在对面的老姑娘。

She slammed the door for a start - 她猛地关上门。slam 猛撞。

She didn’t padlock her tricycle - 她没有锁上三轮车。padlock 挂锁。tricycle 三轮车。

There’s no reflection on you, Chief Inspector, but to leave her tricycle like that, she must have been very upset. 总督察,对你来说没有什么反应(没有什么好奇怪的),但是就这样把她的三轮车丢下,她一定很沮丧。

-I’ll have to go over tomorrow. I still haven’t told the bees. - go over: to make one’s way 开辟新的路。 i.g. go over to store for supplies. 去商店购买日用品。

-I’m sorry?

-Well you have to tell the bees when someone dies. Otherwise they just clear off. - Telling the bees 养蜂人有一个传统,会将重大事件(生老病死婚姻等)告诉蜜蜂,否则上天会使养蜂家庭受到惩罚(比如本片中Miss Bellringer 说蜜蜂会全部走开)。

clock bell chimes - 钟声响起。chime /tʃaɪm/ 1.(钟)响起(尤其是告诉你到几点了);2. 与某某相同或具有相同的效果:e.g. Her views on life didn’t chime with mine. 她的人生观和我不太一致。

tower bell rings.

-Clear off her rocker, if you ask me. - rock: 岩石;前后摇晃,rock music摇滚乐。rocker,摇椅,(摇椅等下面的)两条弯木(用来摇晃)之一;off one’s rocker: 处于极度混乱或精神不健全的状态。in a state marked by extreme confusion or mental unsoundness: … he felt dizzy, slightly off his rocker at this extraordinary assailment of his senses.

-You didn’t believed her?

-Well, what she got to go on? A slammed door and a trike that wasn’t padlocked. It’s a waste of time.

undertaker - 殡仪员。

-I based in Causton but it happens I live here in Badger’s Drift and I thought I ought to pop by. Miss Simpson was a client. 我在Causton上班,但是碰巧我住这里。pop by: 顺便过来一下;pop, (spoken) to go somewhere for a short time.

-I’m sorry?

-She’d pre-paid. Our Satin Service. It’s one of our complete funeral packages. Very up-market, although between you and me. I let her have it at a discount (sniffs). She taught my mom, you know. - Satin,缎面,绸缎,这里应该指服务的等级,类似金卡会员、银卡会员。

-What can I do for you, Mister Rainbird?

-I was wondering if I could take her, the deceased. - decease=death. the deceased去世的人。

-Oh, I’m afraid that won’t be possible for a little while.

-Oh! You do suspect some naughtiness. It was her neck, I undertand. 你确实怀疑有一些捣蛋鬼。致命伤在颈部,我知道的。- naughty 顽皮的;naughtiness 名词,顽皮。

-[Troy] Who told you that?

-Come on, everybody knows that by now. It’s that sort of village.

-[Troy] Well, you can’t have the body yet. All right? Sir?

-[to Barnaby] Oh, I see you’ve got a right constable there. You let me know when you’re ready for me.

-[Troy] See the car?

-Yes.

-You wouldn’t have thought they were so well paid, would you, undertakers? 你应该没有想到殡仪员会获得如此高的报酬,不是吗?

-Check the camera, and the telephones. Find out what calls did Miss Simpson made after six o’clock.

-So you’re taking it seriously then, sir?

-No, Troy, I’m just filling in time until tea.

-Right! Oh, camera and telephone, right. What about you?

-I must find a doctor.

-Something wrong, sir?

-Emily Simpson’s doctor, Troy. Maybe she did suffer from dizzy spells. Maybe she did just fail. Either way, I want to know. - spell 拼写;咒语。

医生的家里

医生的招牌:

DR. TREVOR LESSITER
M.B B.S M.R.C.G.P

PHSICIAN & SURGEON

DR. - Doctor。Trevor Lessiter是医生的名字。

M.B B.S - Bachelor of Medicine, Bachelor of Surgery 内外全科医学士

M.R.C.G.P - Membership of the Royal College of General Practitioners 英国皇家全科医生学院会员资格。pratitioner 从业者。general pratitioner 全科医生。

She is remarkably fit for her age. - 在她这个年龄,她显得非常健康。fit 健康的。

I liked to drop in at the end of my rounds. You know, glass of sherry and all that. - go round to sb’s house 拜访某人。 drop in - 顺便过来。

cricket 板球。

But she never got round to saying what it was. - 她没能说出来是什么事。get round to 做成了一件你因其他事情被耽搁了事。

I’ve got to talk to someone. - 我得这个人说说话。have (got) to 不得不。

-Did she say what it was?

-No.

-Didn’t you press her?

-We’re not meant to. - 我们不是故意的。

-And there was nothing more?

-I’m sorry, Inspector. I know there was something else but I can’t think. 我知道还有些事情,但是我想不起来。

-Well, if it does come to you, can you give us ring? 当你想起来,能不能给我们一个电话。

-Yes, of course.

ring off - 挂断电话。

Inspector - 督察。

scrambled eggs - 炒鸡蛋。scramble 争夺。

Stuck with a heavy object as yet unidentified at the base of the neck. 脖子根部被一个尚未辨认的重物卡住。

sombre music - 阴沉的音乐。

The grass flattened, brambles broken. 草被压扁了,荆棘断了。

What, you think someone’s been having it away? 你认为有人把它们拿走了?

Two people bonking? 两个人搏斗/性交?

tweezers - 镊子。

-A piece of black fibre. 一片黑色纤维。

-Off their clothes. 从他们的衣服上掉下来的?

-No, I don’t think so. I’d say a blanket or rug, something like that. 我认为是毯子或地毯。

I want the whole place gone over. - go over 仔细检查。

Do you really think that’s what it came down to, sir? 你真的认为这就是问题所在吗?

Unless it was adultery. 除非是通奸。

I suppose they could have been arse-bandits. - 我猜想可能他们是屁股小偷(同性恋)。arse(粗鲁的词)屁股。bandit 有武器的小偷。

You mean “homesexuals”, Troy? Troy,你是说同性恋?

You are as politically correct as Nuremberg rally. 你和纽伦堡集会(德国纳粹一年一度的党代会)一样政治正确。

Rainbird家

eerie music - 怪异的音乐。

pot to kettle. 把锅里(的水)倒到壶里,应该是上茶的意思。(影片中,茶水是装在瓷壶里)

eyrie - 是 aerie 的另一种写法,鹰巢。an elevated often secluded dwelling, structure, or position 较高且通常僻静的住宅、结构或位置。If you refer to a place such as a house or a castle as an eyrie, you mean it is built high up and is difficult to reach.

My hide. Yes, I’m a keen observer of wild life, birds. 我的隐藏爱好,我喜欢观察野生动物——鸟。

I thought I saw a pair of binoculars. 我想我看见了一副望远镜。

trolley 手推车。

Do help yourself. 请自便。

widower - 鳏夫。widow 寡妇。

The clubs are anchovy. Salmon spread in the hearts. Marmite spades and potted meat diamonds.

梅花状的anchovy。Salmon spread是心形的。黑桃状的Marmite。方块状的potted meat. - potted: preserved in a pot, jar, or can: potted meat.

Not that you’ll find her there. 并不是说你会在那里找到她。

Done very nicely for herself. 为自己做得很好。

-Iced sombrero, constable. - Iced sombrero冰阔边帽(应该是这种形状的食物),constable 警员。constabulary 警察局。

-No, thank you. And I’m a sergeant.

大不列颠警察等级(由高到低)

Chief constable, Deputy chief constable, Assistant chief constable, Chief superintendent总警司, Superintendent警司, Chief inspector总督察, Inspector督察, Sergeant警长, Constable警员. - 参考维基百科

Detective是警察的前缀之一,比如Detective Chief Inspector。这种警察一般穿便衣,职位和职级和制服警察一样。

-I mean what are you likely to see flying at that time? 我的意思你那个时候想要看什么飞禽?

-Owls. 猫头鹰。

These two give me the creeps. 这两个人让我毛骨悚然。give someone the creeps - to cause someone to have uncomfortable feelings of nervousness or fear:

-You don’t suppose it was him in the woods, do you? 你该不会认为是他在树林里吧?

-I somehow doubt it, Troy. 我有点怀疑。

They certainly had it in for her. 他们当然是为了她。

Barnaby家

‘Tis Pity She’s a Whore. 可惜她是一个妓女,John Ford 导演的音乐剧。’Tis 是 it is 的缩写。

Would you go through my lines with me? 你可以帮我一起练习一下台词吗?

I doubt he’ll have time. 我怀疑他是否有时间。

quail - 鹌鹑。

(Telephone rings) I’ll get it. 我去接电话。

In the pond behind the quarry. 在采石场后面的池塘里。

-Think what the police would make of it if their forensic people got hold of it. 想想警察会怎么想,如果他们的法医人员拿到了它。make of - to have an impression or understanding about something. 对某事有印象或有了解。

-They’d have a field day. 他们会度过愉快的一天。field day 特殊的一天。

-This is the big one, Denny. This is going to make us very, very rich. 这是最重要的,这会让我变得非常富有。

Two colomns in the local rag and a coroner’s re-port. - coroner 验尸官。

Tye House

tyres screech - 轮胎尖叫声。

bright upbeat music - 明亮欢快的音乐。upbeat 乐观的。

-How the other half live?

-Rather less then half I’d say. 我说目前还不是(富豪的)另一半。

estate manager - 物业经理。

-I don’t suppose you were in the village at any time at between six and eight on Wednesday? 我想你周三六点到八点之间的任何时间都不会在村子里?

-No. Don’t remember where I was. Out in the fields. 不在。不太记得我去了哪里。我出去到田野里去了。

drawing room - 客厅。

late wife - 已故的妻子。

as a matter of fact - 事实上。

-If it’s not too painful, sir, I’d be interested to know how your wife died. 如果不是太痛苦的话,先生,我很想知道你妻子是怎么死的。

-It is painful. And I don’t see how it’s relevant. 很痛苦。并且我没有看到(这两件事的)相关性。

-Miss Simpson could have known your wife as Annabella. As a nick name, pet name or something like that. If there is a connection - - Simpson女士可能知道你的妻子是Annabella,一个昵称、爱称或其他啥的。

-There is no connection.

-We need to be sure.

-(sighs) If you insist. It was two years ago… 如果你坚持的话。

And Bella’s sister had come along. Phyllis, Phyllis Cadell. She didn’t shoot that ofen and I always wondered why she closed that day of all days. - Bella的姐妹Phyllis Cadell也来了,她不经常射击,我常常想知道,为什么那天她整天关门(可能是有个私人商店)。

He’d come as a beater, to scare the birds. 他来的任务敲击吓唬鸟。

I suppose it’s always easy to talk about these thing with hindsight but I’m often felt think we were ill-fated that day. 我想事后谈论这些事情总是很容易的,但我常常觉得我们那天运气不好。

Bella tripped on a root and twisted her ankle rather badly. - Bella被树根绊倒并且脚踝被扭伤得非常严重。

But by the time ambullance arrived it was all over. 但当救护车到达时,一切都结束了。

dog whines - 狗呜呜声。

generator - 发电机。

marquee - 帐篷。

You finished it, I take it? (警官)你的问讯结束了吧?我可以做其他的事情吧?

He was a sort of guardian. 他是某种守护者。

We won’t take up any more or your time. 我们不再占用您的时间了。

exhale - 呼气。

But I do what I can even I’m quite worn out. - 我尽我所能帮忙,即使我累坏了。wear 磨损。

mistress - 女主人,具有权威或控制地位的女人;情妇。

Henry has a cottage on the estate and I’m being pensioned off there. I’m quite looking forward to it.

Pathetic. - 可怜的。

She was scared shitless. - 她被吓得屁滚尿流。

You do have a way with words, don’t you?

What are we investigating, sir? Emily Simpson or Belly Trace?

There’s no point asking me about it. 没有必要问我这个问题。

I don’t have anything to do with the village. And the village doesn’t have much to do with me.我和那村子没有任何关系。那村子和我也没有太大关系。

-Could you tell me where you were on last Wednesday?

-No. I don’t know. Maybe I’m here, I’m most days.

-Not much of life. 没什么生活。

-My work is my life. You wouldn’t understand that. 我的工作就是我的生活。你不会理解这一点。I might have gone for a walk or something, I don’t remember.

Missis - Miss, Misses 小姐。

I ran hell for leather back to Tye House. - hell表示程度,加强语气。

I’ll say one thing for Katherine. She certainly doesn’t come cheap. 我要为Katherine说一件事,她的价格当然不便宜。

Barnaby家

intense uneasy music - 强烈不安的音乐。

-This noble creature was in every part. So angel-like, so glorious, that a woman, who was not human, as was I – 这个高贵的生物无处不在。

-Had not been but human. 只不过是人类。

-Who had not been but human, as was I. Would have kneeled to him and begged for love. 谁不是人类,就像我一样。会向他下跪并乞爱。You, why you are not worthy once to name. His name without true worship, or indeed. Unless you kneeled, to have another name him. 你,为何连一次的名字都不配。 他的名字没有真正的崇拜,或者说确实如此。 除非你跪下来给他起另一个名字

-What was he called?

-We not come to that. 我们并没有谈到这个。Let it suffice that you shall have the glory. 只要你拥有荣耀就足够了。To father what so brave a father got. 对于父亲来说,一个父亲有多么勇敢。

That sounded good. It’s coming along.

She’s wonderful. We’re gonna have to go up and see it.

-If I ever manage to learn it all. 如果我能学会这一切就好了。manage to do 设法做,(尽管有困难)成功做。

I’ve got a nice Pot-au-feu in the deep freeze. 我有一份美味的冷冻炖锅。Pot-au-feu (/ˌpɒtoʊˈfɜːr/; French: [pɔt‿o fø] ( listen); “pot on the fire”) is a French dish of slowly boiled meat and vegetables, usually served as two courses: first the broth (bouillon) and then the meat (bouilli) and vegetables.

horse nickers - nicker: 1, (of a horse) give a soft, low, breathy whinny. 2, a nickering sound.

white lilies - 白百合。

This is the Satin Service.

Whimsical sombre music - 异想天开的忧郁音乐。

You’ve withdrawn 500 pounds from our joint reserve account. 您已经从我们的联合储蓄账户中提取了500英镑。

overdraw - 透支。

I thought I’d leave you two to bicker in private. 我想我应该让你俩私下斗嘴。

I know that my redeemer liveth, and that he shall stand upon the last on the earth. Whom I shall see for myself, and mine eyes shall behold, and not another.(祷告)我知道我的救世主还活着。- mine 用在元音之前,相当于my.

Missis Rainbird no more a bird-wather than I am. - Rainbird女士和我一样都不是鸟类观察者。

personalised Porsche. 个性化的保时捷。

Rain stopped play. 雨停止了比赛。

His wife’s just as bad. 他的妻子同样糟糕。

It’s early closing. 关门还早呀。

There’s something wrong and something that doesn’t add up. 有些地方出了问题,有些地方不合逻辑。

Maybe he was. Maybe he simply mistaken in his account. But he wasn’t telling us the truth. 他可能是(在撒谎),也可能只是记错了。但是他没有告诉我们事实。

Why did he run all the way back to Tye House to call the ambullance when the accident happened on the other side of the village? 事故发生在村子的另一边,为什么他还要千里迢迢跑回The House叫救护车呢?

-It seems they’re all bloody liars. 看起来他们都是该死的撒谎者。bloody - used to express anger or to emphasize what you are saying in a slightly rude way.

-One of them is something more. 其中一个有更多东西。

Forasmuch as it hath pleased Almighty God of his great mercy to take unto himself, the soul of our dear sister here departed, we therefore commit her body to the ground; earth to earth, ashes to ashes, dust to dust; Amen.

It’s early days yet. 现在还早呢。

Not for poor Emily.

Come and have sherry. 来喝杯雪莉酒吧!I feel the need of a drink. I’m afraid funerals do that for me. 我觉得需要喝一杯,恐怕葬礼对我来说就是这样。

polio - 脊髓灰质炎。

pensive music - pensive沉思的。

She adored him. Still does for all I know. - 她崇拜/喜欢他,据我所知(for all I know)仍然如此。

She was Herry’s ward. 她是Herry的被监护人。

Herry sort of adopted them. - Herry有点收养了他们。

set them up in a gamekeeper’s cottage on the estate. - 把他们放在庄园的猎场看守人的小屋里。

They are very young then, barely in their teens. - 他们那时候还很小,才十几岁。

nanny - 保姆。

There was a nanny, Mary Sharpe, Nanny Sharpe, which was meant to look after them. - 有一个保姆,叫Sharpe,是为了照顾他们。

-But she had a terrible time. 但是她度过了一段糟糕的时光。

-In what way? 以什么样的方式?

-The children were always fighting. Endless rows. - 孩子们总是打架,无休止地争吵。row 可数名词,争吵:A row is a serious disagreement between people or organizations.

In the end, Mary upped and left. - 最后,Mary起身离开了。up 动词,增加;突然离开:If you up and leave a place, you go away from it, often suddenly or unexpectedly.

Now she’s retired down on the coast. 现在她在海边退休了。

-If you ask me, Katherine is the one to look out for. 如果你问我,凯瑟琳是值得留意的人。

-Meaning? 意思是?

-That girl is far too beautiful for other people’s good. 那个女孩太漂亮了,不利于别人。That girl is far too beautiful for other people’s good. If she was found bonking in the wood, she has the most to lose. 如果她被发现在树林里打滚(性交),她的损失将是最大的。

She’s got a point. 她说得有道理。

it barks its head off. 它拼命狂叫。its head在这里表示强烈程度。You’d have heard it a mile away! 你一英里外都能听见它。

Damn! Do you know, for a minute I thought I had the whole thing solved. 该死!你知道吗,有一瞬间我以为我已经解决了整个问题。

I think I deserve another Marron Lyonnaise. - 我认为我值得再来一份我值得再来一份马龙·里昂酱。

I want their clothes bagged and down forensics. - 我想把他们的衣服打包并取证。forensics法医。

What a mess. - 真是一团糟。

She’s being treated for shock outside, no surprise. - 她休克了,正在外面接受治疗,这并不奇怪。shock休克。

Don’t expect to get much sense. - 不要指望得到太多意义。

You’d better come up and take a look at this. 你最好过来看看这个。

-You’re not going to believe it. 你不会相信的。

-On the contrary, Troy, I rather think I will. 恰恰相反,我觉得我会相信的。

What was it she said, sir? 先生,她说了什么?

Listen to this: At 10:30 a.m. Mister and Missis W crossed over by post box to avoid Miss G. 10点30分,W先生和W小姐穿过邮政信箱以避免G小姐。

11:00 a.m. A called on Miss S., stayed 15 minutes. 上午11:00,A拜访了S小姐,停留了15分钟。

There must be a couple of hundred entries in this file alone. 仅这个文件中就得有上百个条目。May thousands of them over the years. 可能有这几年的上千条记录。

I want them all taken down. 我希望他们都被记录下来了。take down 1, 记录write down; 2, 拆除dismantle: wall, fence etc.

We’re gonna have to go through the whole lot of them. 我们不得不要把它们全部浏览一遍。

blackmail - n. & vt. 勒索。

She wasn’t a bad old stick. 她不是一个很坏的人。

She is a bit perculiar, her and her son. Him being au undertaker and all. - 她和她的儿子有点奇怪。他是殡仪馆的承办人等等。perculiar - 奇特的。

But she was very good for me, in her own way, very good to me.

One is getting wed. 将要结婚的那个。

-That’s a bend just ahead. 前面就是一个转弯。

-Now, I’ve seen it, sir. 我看到了。

And do me a favor, Troy, when we get there, if we get there, park at the bottom of the lane. 帮我一个忙,特洛伊,当我们到达那里时,如果我们到达那里,请将车停在车道的底部。

yells - 呼喊。

Sometimes you really make me sick. 有时你真的让我感到恶心。

I don’t care if you marry him for money, but why can’t you come clean and admit it? 我不在乎你嫁给他是不是为了钱,但你不坦白承认。come clean 坦白说出来。admit 承认。

It’s not like that. 不是那样的。

So what is it like? Tying yourself to a bloody cripple at your age. 在你这个年纪,把自己绑在一个该死的瘸子身上。tying - tie的现在分词。

That bloody cripple looked after us. If it hadn’t been for him, we wouldn’t have had a home. We wouldn’t have had anything.

Yes, he’s getting his pound of flesh, isn’t he? - 是的,他正在得到一磅肉(意思是买到回报)。

He’s not buying me, Michael.

So what is he doing then? Renting you by the hour? 那他现在是做什么?按小时租赁你吗?

slaps - 拍击。

Alright, then. Don’t come to our wedding. Henry and I are better off without you. 那好吧。不要来参加我们的婚礼。没有你,亨利和我会过得更好。be better off - If you say that someone would be better off doing something, you are advising them to do it or expressing the opinion that it would benefit them to do it: If you’ve got bags you’re better off taking a taxi.

I won’t bother buying a present, then!

-Do you want to go follow her, sir?

-No, Troy, I’d like to take a closer look in here.

-What? Go in without a warrant? Isn’t that a bit? - 什么?没有搜查令就进去?warrant - 保证;值得,有必要;搜查令;做某事的依据。

-You have a problem, Troy?

-No, no. Just glad I didn’t suggest it. 只是庆幸我没如此建议。

-If anybody finds us, you did.

-Pity. 真遗憾。

-Locked? 锁上了?

-Yep.

-I can force it. 我可以强行弄开它。

Thank you all the same.

-Mom gone to bed? 妈妈已经睡了吗?

-Hours ago. 几小时前(就睡了)。What’s all this? 这到底是什么?

-Notebooks. Iris Rainbrid took a Neighbourhood Watch to unheard of extremes. - Iris Rainbrid将邻里守望者组织带到了前所未闻的极端。extreme - 极端。

You wouldn’t think that one small village could have so much trouble bubbling under the surface.

-Was it very horrid? The bodies.

-I’ve seen worse.

I’m one more step further down the road. - 我在路上又向前迈进了一步。

-I haven’t read lines with you. How’s it going?

-Oh well, four acts down, one to go. - 四幕已结束,还剩一幕。

-Yes, I suppost it’s the last act that really matters. 是的,我认为真正重要的是最后一幕。

car rumbles - 车隆隆地。

peacock hoots - 孔雀叫。

It’s out of the question. - 这是不可能的。

Voice of sanity. 理智的声音。

Parish Council - 教区议会。

It was only later I realised. 后来我才意识到。

Everything’s over, it’s all slipping away. 一切都结束了,一切都过去了。

-I don’t suppose you saw anyone in the woods? 我想你在树林里没有看到任何人吧?

-No. 没有看到。

Phillips Codell, I’m here arresting you on suspicion of the murder of Bella Trace on 26th of June 1995.

You don’t have to say anything, but it may harm your defence if you do not mention when questioned something that you reply on in court. Anything you do say may be given in evidence.

He was in that wheelchair and she just couldn’t cope.

It’s something one does in the country. 这是国内每个人都会做的事情。

I took a hip flask, filled with vodka and I kept on drinking. It was the only that I could get the courge.

All the dead birds. The noise, the blood that made me feel sick and dizzy. 到处都是死鸟。噪音、血液让我感到恶心和头晕。

I didn’t think I was gonna be able to do it.

I doubled back behind the trees and managed to hide. - 我折回树后并设法躲了起来。double back, to turn and go back in the direction you have come from.

Then I waited until I had a clear shot. And then. I shot her. 然后我就等到了清晰的视角。然后,我就开枪打了她。第一个shot是“镜头”的意思,第二个shot,是shoot的过去式及过去分词。

It was terrible. I saw her pitch forward and fall to the ground. - 太可怕了。我看到她向前倾倒,倒在了地上。pitch, to move or be moved suddenly, especially by throwing or being thrown.

And then, I just panicked. 然后,我就惊慌失措了。panickis a common misspelling of panic.

I got up and I ran and I ran.

I thought then that I’d done it, that I got away with it. 那时我想我已经做到了,我逃脱了惩罚。

How could I have known that I’d been seen? 我想知道,我是怎么被看见的?

She put it all in those notebooks, didn’t she? I had to go to that revolting house.

I expect you’ll be needed more than ever at Tye House now. 我预计Tye House现在比以往任何时候都更需要你。Quite the chatelaine you’ll be, won’t you? Now, what will you have?

dramatic siniter music - 戏剧性的险恶音乐

The diamonds are marmite, the spades are jam, the hearts are tuna and the clubs are sandwich spread. 方块是马麦酱,黑桃是果酱,红心是金枪鱼,梅花是三明治。

spread - 放在面包或饼干上的软质食物(酱)。a soft food for putting on bread and crackers:

cheese/chocolate/fish spread

There’s bread and various spreads for tea.

voiceover - 画外音。

How much did they take? 他们拿了多少钱?

They’d even stopped asking me. They knew I was cleaned out. 他们甚至不再找我要了。他们知道我被掏空了。

Sir, there’s someone here for you in reception. 先生,有人在接待处等候您。

There’s something about that story, the shooting party, that still not right.

You know you featured in here? 你知道你自己被包括在这个笔记本中了吗?

He was wearing his denims and that cap he wears. 那个人穿着他的牛子裤和帽子。

brutal - 野蛮的。

-You again. You don’t give up, do you?

-Mister Lacey, we’re here in connection with the death of Iris Rainbird.

-In connection with. You policemen have a wonderful way of expressing yourselves.

-As you may know, Mister Lacey, she was murdered in a particularly brutal fashion. 你可能知道,莱西先生,她是被以一种特别残酷的方式谋杀的。

-I hope you’re not looking for insincere expressions of regret on my part, Chief Inspector. 我希望你不是在寻找我不真诚的遗憾表示,总督察。She was a very nasty woman. 她是个令人讨厌的女人。

-Did you ever go to her house?

-No.

-So what would you say if I told you that somebody had been you entering her front door shortly after four o’clock yesterday afternoon?

-I would say they needed their eyes testing.

-(Troy) Mister Lacey, we have a warrant here to search these premises. - premises, 某人(一般是公司或组织)拥有的土地和建筑the land and buildings owned by someone, especially by a company or organization. premise, 前提。

-So how do you explain this, Sir?

-I can’t! Of course I can’t!

-Where have you put the clothes?

-What clothes?

-The dungarees, the cap and the golves. 工作服、帽子和手套。

-What?

-The clothes you wore to kill Iris Rainbird.

-You’re raving mad! 你疯了吧!rave, to speak in an uncontrolled way, usually because you are upset or angry, or because you are sick.

I’ve been framed. 我被陷害了。

a custody death.

-Maybe we should have put her on suicide watch, sir?

-Is that a reprimant, Troy? ‘Cause you’re right. This is my fault.

-Maybe she’s better off this way. All things considered.

-That is not the point.

Lacey has been shouting his mouth off, sir. 莱西一直在大喊大叫。

door clanks. 门叮当响。

How nice of you to look in, Chief Inspector.

-You say what you’ve got to say and get on with it. 你说出你必须说的话,然后继续说下去。

-I want to go home.

-Aren’t you, Mister Comedy? You want the truth, Mister Lacey. I’ve had you up to here. 我几乎都查出你的罪了。

You were in such a hurry to drag me off yesterday. 你昨天那么急着把我拖走。

mid-morning - 上午中旬。

Caped Crusader - 斗篷十字军

He only did the first sketches but they took all day. 他只画了草图,但是这些草图花了一天的时间。

He said I had a wonderful complicated face.

He’s a surrealist, is he? 他是超现实主义者,是吗?

-And since everyone’s always picking on him, you might as well know he was there the night Emily Simpson died too. 既然每个人都在找他的茬,你不妨知道艾米丽·辛普森去世的那天晚上他也在他的工作室里。

-You’ve seen quite a bit of him, is there something that I ought to know? 你已经和他见过不少次面了,有没有什么事是我该知道的?(你有没有和他发生过什么?)

-What? Something like you and your Missis Whiplash? Or Barbara and all her boyfriends? No, dad, there’s nothing you need to know at all. 什么事?就像你和Whiplash太太那样吗?或者Barbara和她的那些男朋友一样?没有,爸爸,没有什么事是你应该知道的(我和他没有发生那样的事)。

In fact I think she may have told us more than she meant to. 事实上我认为她告诉了我们比她本意更多的事情。

-It’s very good.

-It’s only Marks and Sparks, I’m afraid. You should have told me you were coming.

-Marks and Sparks is fine.

The Lessiter girl backed up his alibi. 莱斯特女孩支持了他的不在场证据。

It had to be a trick. 这一定是一个诡计。

car honks. 汽车鸣笛。

I have to be off. 我要走了。

Burnham Crescent - Burnham发音为[BUR] + [NUHM]。crescent雕刻成的类似新月的形状。

Up ahead this road on the left. 往这条路前面的左边走。

They were not easy children but of course under the circumstances, one had to make allowances. 他们不是好孩子,但当然在这种情况下,人们必须体谅他们。

Every day it was a slanging match. 每天都是一场谩骂比赛。She’d scream at him and he’d fling himself out of the house.

cup shatters. 杯子粉碎。

How could I’ve betrayed them? 我怎么可能背叛他们?

All she had to do was to hand the dog over to her brother. 她所要做的就是把狗交给她哥哥。

Why wouldn’t he open the door. Because then she’d have seen the dog and that would have spoiled the whole set-up. 那会破坏整个设计。

If it hadn’t been for an observant neighbour and an unlocked tricycle, we’d have never been any the wiser. 如果没有细心的邻居和一辆没上锁的三轮车,我们永远不会变得更聪明。

Yes, they’re clever, weren’t they? Always working off one another.

Whoever went to the house was wearing overalls and a cap and they probably made sure they were seen at least from behind. - overalls工作服。

Katherine stabbed them and then she put the knife and the blood-soaked overalls into the basket.

Bella Trace was just a freak change, wrong place, wrong time.

makesman - 制造者。

bludgeon, poison, stab

sheep bleat - 羊咩咩叫。

“I’ve been framed.” And he made this sign. It was a coded message. He was warning her to remove the picture. - 我把画装在框里了。frame, 把画装框,When a picture or photograph is framed, it is put in a frame.

It’d have given the game away, wouldn’t it? 这幅画泄露了这个游戏,不是吗?give away泄露,If you give away information that should be kept secret, you reveal it to other people.

-It’s powerful. It’s brilliant even in its own way.

-He had talent.

-But so twisted.

-I almost guessed it when we came here. The three bedrooms and only one bed slept in. They pulled the wool right over my eyes.

-(Troy) When?

-That time we came here and they were arguing. They really did seem to hate each other, didn’t they? And they couldn’t have staged it for our benefit. Because they didn’t know we were here. Except they did. They saw us in the mirror. And they did put on a show.

-Poor Emily.

-(Troy) And poor Annabella. Who was she?

-I don’t suppose we’ll ever know.

I hope you’re not gonna fall asleep in this.

I wouldn’t dream of it.

Anyway, after what you’ve just been through, a start of incest should be right up your street.

Come this in sadness from you.

Let some mystery befall me soon if I dissemble all.