$ which rpcgen /bin/rpcgen $ rpcgen usage: rpcgen infile rpcgen [-abkCLNTM][-Dname[=value]] [-i size] [-I [-K seconds]] [-Y path] infile rpcgen [-c | -h | -l | -m | -t | -Sc | -Ss | -Sm] [-o outfile] [infile] rpcgen [-s nettype]* [-o outfile] [infile] rpcgen [-n netid]* [-o outfile] [infile] options: -a generate all files, including samples -b backward compatibility mode (generates code for SunOS 4.1) -c generate XDR routines -C ANSI C mode -Dname[=value] define a symbol (same as #define) -h generate header file -i size size at which to start generating inline code -I generate code for inetd support in server (for SunOS 4.1) -K seconds server exits after K seconds of inactivity -l generate client side stubs -L server errors will be printed to syslog -m generate server side stubs -M generate MT-safe code -n netid generate server code that supports named netid -N supports multiple arguments and call-by-value -o outfile name of the output file -s nettype generate server code that supports named nettype -Sc generate sample client code that uses remote procedures -Ss generate sample server code that defines remote procedures -Sm generate makefile template -t generate RPC dispatch table -T generate code to support RPC dispatch tables -Y path directory name to find C preprocessor (cpp)
For bug reporting instructions, please see: <http://www.gnu.org/software/libc/bugs.html>.
rpcgen provides an additional preprocessing feature: any line that begins with a percent sign (%) is passed directly to the output file, with no action on the line’s content. Use caution because rpcgen does not always place the lines where you intend. Check the output source file and, if needed, edit it.
eyelashes makeup hairstyle/hairdo get my hair done hair gel buzz cut helmet When you have a lot of hair, the helmet makes your hair flat. hair colouring
In general, when a program enters a signal handler in a multi-threaded environment, the behavior regarding other threads depends on how the signal handler is set up and the specific signal that is being handled.
Default Behavior: By default, when a signal is delivered to a process, it interrupt the thread that is currently running and executes the signal handler in the context of that thread. Other threads in the process continue running unless they are also interrupted by signals.
Thread-Specific Signal Handling: Some signals, such as SIGINT (interrupt signal), SIGTERM (termination signal), or SIGABRT (abort signal), are typically delivered to the entire process, which means they can interrupt any thread. However, other signals, like SIGSEGV (segmentation fault) or SIGILL (illegal signal), are usually delivered to the specific thread that caused the signal.
Signal Masking: In a multi-threaded program, you can use signal masking (sigprocmask in POSIX systems) to block certain signals in specific threads. This can affect whether a signal handler interrupts a particular thread or not.
Asynchronous-Signal-Safe Functions: Signal handlers should only execute functions are considered “asynchronous-signal-safe” according to POSIX standards. These functions are designed to be safe to call from within a signal handler. Using non-safe functions in a signal handler can lead to undefined behavior.
// Define your pipeline body classMyPipeline { public: voidoperator()(tbb::flow_control& fc)const{ // Your pipeline logic here // ... // Inform the pipeline that there is no more data fc.stop(); } };
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 voidprocess_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) ; }
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); });
$ 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.
// 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),那么该线程被允许拿取第一个循环的任务来执行。这会导致即使是同一个线程内,也可出现乱序执行的情况。在大多数情况下,这没有什么危害。
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! } );
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 } );
intmain(){ constint 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 } ); return0; }
# 进入其他版本的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
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:
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.
intmain(){ 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]); }
-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
$ 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)