09 - POSIX 绑定
第 9 章:POSIX 绑定
Vala 编译为 C,天然具备调用 POSIX API 的能力。本章将介绍如何通过 Vala 进行系统级编程。
9.1 POSIX 与 GLib 的关系
Vala 通过两条路径访问系统 API:
┌──────────────────────────────────────────┐
│ Vala 源代码 │
│ ┌──────────┴──────────┐ │
│ GLib/GIO 绑定 POSIX 绑定 │
│ (跨平台, 推荐) (直接系统调用) │
│ │ │ │
│ GLib C API POSIX C API │
│ │ │ │
│ └──────┬────────────┘ │
│ Linux/POSIX 内核 │
└──────────────────────────────────────────┘
| 路径 | 优点 | 缺点 |
|---|---|---|
| GLib 绑定 | 跨平台、自动内存管理 | 功能有限 |
| POSIX 绑定 | 功能完整、性能好 | 平台相关 |
9.2 文件 I/O
9.2.1 GLib 文件操作(推荐)
void main () {
// 写入文件
try {
GLib.FileUtils.set_contents (
"/tmp/test.txt",
"Hello, Vala!\n这是测试内容。\n"
);
print ("文件写入成功\n");
} catch (GLib.FileError e) {
printerr ("写入失败: %s\n", e.message);
}
// 读取文件
try {
string content;
size_t length;
GLib.FileUtils.get_contents ("/tmp/test.txt", out content, out length);
print ("文件内容 (%zu 字节):\n%s\n", length, content);
} catch (GLib.FileError e) {
printerr ("读取失败: %s\n", e.message);
}
// 追加写入
try {
var stream = GLib.FileStream.open ("/tmp/test.txt", "a");
if (stream != null) {
stream.puts ("追加的内容\n");
stream.flush ();
}
} catch (GLib.Error e) {
printerr ("追加失败: %s\n", e.message);
}
// 检查文件是否存在
bool exists = GLib.FileUtils.test (
"/tmp/test.txt", GLib.FileTest.EXISTS
);
print ("文件存在: %s\n", exists.to_string ());
// 获取文件信息
try {
int64 size;
GLib.FileUtils.get_contents ("/tmp/test.txt", null, out size);
print ("文件大小: %lld 字节\n", size);
} catch (GLib.FileError e) {
printerr ("错误: %s\n", e.message);
}
}
9.2.2 GLib FileStream
void main () {
// 使用 FileStream(类似 C 的 FILE*)
var stream = GLib.FileStream.open ("/tmp/data.csv", "w");
if (stream == null) {
printerr ("无法打开文件\n");
return;
}
// 写入 CSV 数据
stream.printf ("姓名,年龄,城市\n");
stream.printf ("张三,30,北京\n");
stream.printf ("李四,25,上海\n");
stream.printf ("王五,28,广州\n");
stream.flush ();
// 读取文件
var reader = GLib.FileStream.open ("/tmp/data.csv", "r");
if (reader != null) {
string line;
while ((line = reader.read_line ()) != null) {
print (" %s\n", line);
}
}
}
9.2.3 异步文件 I/O
public async void read_file_async (string path) throws GLib.Error {
var file = GLib.File.new_for_path (path);
// 异步读取
var stream = yield file.read_async (GLib.Priority.DEFAULT, null);
var data_stream = new GLib.DataInputStream (stream);
string line;
size_t length;
while ((line = yield data_stream.read_line_async (
GLib.Priority.DEFAULT, null, out length)) != null) {
print ("%s\n", line);
}
yield stream.close_async (GLib.Priority.DEFAULT, null);
}
public async void write_file_async (string path, string content)
throws GLib.Error
{
var file = GLib.File.new_for_path (path);
var stream = yield file.replace_async (
null, false, GLib.FileCreateFlags.NONE,
GLib.Priority.DEFAULT, null
);
yield stream.write_async (
content.data, GLib.Priority.DEFAULT, null
);
yield stream.close_async (GLib.Priority.DEFAULT, null);
}
void main () {
var loop = new GLib.MainLoop ();
write_file_async.begin ("/tmp/async.txt", "异步写入的内容\n", (obj, res) => {
try {
write_file_async.end (res);
print ("异步写入完成\n");
read_file_async.begin ("/tmp/async.txt", (obj2, res2) => {
try {
read_file_async.end (res2);
} catch (GLib.Error e) {
printerr ("读取错误: %s\n", e.message);
}
loop.quit ();
});
} catch (GLib.Error e) {
printerr ("写入错误: %s\n", e.message);
loop.quit ();
}
});
loop.run ();
}
9.2.4 目录操作
void main () {
// 创建目录
try {
GLib.DirUtils.create ("/tmp/testdir", 0755);
print ("目录创建成功\n");
} catch (GLib.Error e) {
printerr ("创建目录失败: %s\n", e.message);
}
// 创建嵌套目录
try {
GLib.DirUtils.create_with_parents ("/tmp/a/b/c", 0755);
print ("嵌套目录创建成功\n");
} catch (GLib.Error e) {
printerr ("错误: %s\n", e.message);
}
// 列出目录内容
try {
var dir = GLib.Dir.open ("/tmp");
string? name;
while ((name = dir.read_name ()) != null) {
string full_path = GLib.Path.build_filename ("/tmp", name);
print (" %s\n", full_path);
}
} catch (GLib.Error e) {
printerr ("错误: %s\n", e.message);
}
// 递归遍历目录
print ("\n递归遍历 /tmp/testdir:\n");
traverse_dir ("/tmp/testdir");
// 删除目录
try {
GLib.DirUtils.remove ("/tmp/testdir");
print ("目录删除成功\n");
} catch (GLib.Error e) {
printerr ("删除失败: %s\n", e.message);
}
}
void traverse_dir (string path) {
try {
var dir = GLib.Dir.open (path);
string? name;
while ((name = dir.read_name ()) != null) {
string full_path = GLib.Path.build_filename (path, name);
print (" %s\n", full_path);
if (GLib.FileUtils.test (full_path, GLib.FileTest.IS_DIR)) {
traverse_dir (full_path);
}
}
} catch (GLib.Error e) {
printerr ("遍历错误: %s\n", e.message);
}
}
9.3 进程管理
9.3.1 启动外部进程
void main () {
// 简单的命令执行
try {
int exit_status;
string std_out;
string std_err;
GLib.Process.spawn_command_line_sync (
"ls -la /tmp",
out std_out,
out std_err,
out exit_status
);
print ("输出:\n%s\n", std_out);
print ("退出码: %d\n", exit_status);
if (std_err.length > 0) {
printerr ("错误:\n%s\n", std_err);
}
} catch (GLib.Error e) {
printerr ("执行失败: %s\n", e.message);
}
}
9.3.2 异步进程执行
public async int run_command (string command) throws GLib.Error {
string[] argv;
try {
GLib.Shell.parse_argv (command, out argv);
} catch (GLib.Error e) {
throw e;
}
int exit_status;
string std_out;
string std_err;
// 使用 spawn 同步版本(简化示例)
GLib.Process.spawn_sync (
null, // 工作目录
argv, // 命令和参数
null, // 环境变量
GLib.SpawnFlags.SEARCH_PATH,
null, // 子进程设置
out std_out,
out std_err,
out exit_status
);
print ("输出:\n%s\n", std_out);
if (std_err.length > 0) {
printerr ("错误:\n%s\n", std_err);
}
return exit_status;
}
void main () {
var loop = new GLib.MainLoop ();
run_command.begin ("uname -a", (obj, res) => {
try {
int status = run_command.end (res);
print ("退出码: %d\n", status);
} catch (GLib.Error e) {
printerr ("错误: %s\n", e.message);
}
loop.quit ();
});
loop.run ();
}
9.3.3 使用 Subprocess(GIO 推荐)
void main () {
try {
// 创建子进程
var subprocess = new GLib.Subprocess (
GLib.SubprocessFlags.STDOUT_PIPE | GLib.SubprocessFlags.STDERR_PIPE,
"echo", "Hello from subprocess"
);
// 读取输出
var stdout_stream = subprocess.get_stdout_pipe ();
var data_stream = new GLib.DataInputStream (
new GLib.UnixInputStream (stdout_stream, true)
);
string line;
size_t length;
while ((line = data_stream.read_line (null, out length)) != null) {
print ("子进程输出: %s\n", line);
}
// 等待子进程完成
subprocess.wait (null);
int status = subprocess.get_exit_status ();
print ("退出码: %d\n", status);
} catch (GLib.Error e) {
printerr ("错误: %s\n", e.message);
}
}
9.3.4 进程管道
void main () {
try {
// 管道连接多个命令
var proc1 = new GLib.Subprocess (
GLib.SubprocessFlags.STDOUT_PIPE,
"ls", "-la"
);
var proc2 = new GLib.Subprocess (
GLib.SubprocessFlags.STDIN_PIPE | GLib.SubprocessFlags.STDOUT_PIPE,
"grep", ".vala"
);
// 获取 proc1 的输出
var stdout1 = proc1.get_stdout_pipe ();
// 传递给 proc2 的输入
var stdin2 = proc2.get_stdin_pipe ();
// 复制数据
var data_stream = new GLib.DataInputStream (
new GLib.UnixInputStream (stdout1, true)
);
string line;
while ((line = data_stream.read_line (null, null)) != null) {
stdin2.write ((line + "\n").data);
}
stdin2.close ();
// 读取最终输出
var stdout2 = proc2.get_stdout_pipe ();
var final_stream = new GLib.DataInputStream (
new GLib.UnixInputStream (stdout2, true)
);
while ((line = final_stream.read_line (null, null)) != null) {
print ("%s\n", line);
}
} catch (GLib.Error e) {
printerr ("错误: %s\n", e.message);
}
}
9.4 线程编程
9.4.1 基本线程
void main () {
print ("主线程开始\n");
// 创建线程
var thread1 = new GLib.Thread<string> ("worker1", () => {
for (int i = 0; i < 5; i++) {
print (" [线程1] 工作中... %d\n", i);
GLib.Thread.usleep (500000); // 0.5 秒
}
return "线程1完成";
});
var thread2 = new GLib.Thread<string> ("worker2", () => {
for (int i = 0; i < 3; i++) {
print (" [线程2] 工作中... %d\n", i);
GLib.Thread.usleep (800000); // 0.8 秒
}
return "线程2完成";
});
// 等待线程完成
string result1 = thread1.join ();
string result2 = thread2.join ();
print ("结果1: %s\n", result1);
print ("结果2: %s\n", result2);
print ("主线程结束\n");
}
9.4.2 线程安全:互斥锁
// 共享数据
private int shared_counter = 0;
private GLib.Mutex mutex = GLib.Mutex ();
void worker (string name, int iterations) {
for (int i = 0; i < iterations; i++) {
mutex.lock ();
shared_counter++;
print ("[%s] 计数器: %d\n", name, shared_counter);
mutex.unlock ();
GLib.Thread.usleep (100000); // 0.1 秒
}
}
void main () {
print ("=== 互斥锁示例 ===\n");
var t1 = new GLib.Thread<void> ("t1", () => { worker ("线程1", 5); });
var t2 = new GLib.Thread<void> ("t2", () => { worker ("线程2", 5); });
var t3 = new GLib.Thread<void> ("t3", () => { worker ("线程3", 5); });
t1.join ();
t2.join ();
t3.join ();
print ("最终计数器: %d (应为 15)\n", shared_counter);
}
9.4.3 条件变量
private GLib.Mutex mutex = GLib.Mutex ();
private GLib.Cond cond = GLib.Cond ();
private bool data_ready = false;
private string shared_data = "";
void producer () {
for (int i = 0; i < 5; i++) {
GLib.Thread.usleep (1000000); // 1 秒
mutex.lock ();
shared_data = "数据 #%d".printf (i);
data_ready = true;
print ("[生产者] 生产: %s\n", shared_data);
cond.signal (); // 通知消费者
mutex.unlock ();
}
mutex.lock ();
shared_data = "DONE";
data_ready = true;
cond.signal ();
mutex.unlock ();
}
void consumer () {
while (true) {
mutex.lock ();
while (!data_ready) {
cond.wait (mutex); // 等待信号
}
if (shared_data == "DONE") {
mutex.unlock ();
break;
}
print ("[消费者] 消费: %s\n", shared_data);
data_ready = false;
mutex.unlock ();
}
}
void main () {
print ("=== 生产者-消费者示例 ===\n");
var producer_thread = new GLib.Thread<void> ("producer", producer);
var consumer_thread = new GLib.Thread<void> ("consumer", consumer);
producer_thread.join ();
consumer_thread.join ();
print ("完成\n");
}
9.4.4 线程池
void main () {
// 使用 GLib 线程池
var pool = new GLib.ThreadPool<WorkItem> (
worker_func,
4, // 最大线程数
false // 不独占
);
// 添加任务
for (int i = 0; i < 10; i++) {
var item = new WorkItem ("任务_%d".printf (i));
pool.add (item);
}
// 等待一段时间让任务完成
GLib.Thread.usleep (5000000);
print ("所有任务已提交\n");
}
public class WorkItem : Object {
public string name { get; set; }
public WorkItem (string name) {
Object (name: name);
}
}
void worker_func (owned WorkItem item) {
print ("处理: %s (线程: %p)\n", item.name, (void*) GLib.Thread.self ());
GLib.Thread.usleep (500000); // 0.5 秒
}
9.4.5 异步队列
void main () {
// 创建异步队列
var queue = new GLib.AsyncQueue<string> ();
// 生产者线程
var producer_thread = new GLib.Thread<void> ("producer", () => {
for (int i = 0; i < 10; i++) {
string item = "消息 #%d".printf (i);
queue.push (item);
print ("[生产] %s\n", item);
GLib.Thread.usleep (300000);
}
queue.push ("QUIT");
});
// 消费者线程
var consumer_thread = new GLib.Thread<void> ("consumer", () => {
while (true) {
string? item = queue.pop (); // 阻塞等待
if (item == "QUIT") break;
print ("[消费] %s\n", item);
}
});
producer_thread.join ();
consumer_thread.join ();
print ("完成\n");
}
9.5 网络编程
9.5.1 TCP 客户端
void main () {
try {
// 解析地址
var resolver = GLib.Resolver.get_default ();
var addresses = resolver.lookup_by_name ("example.com", null);
foreach (var addr in addresses) {
print ("地址: %s\n", addr.to_string ());
}
// 创建 Socket 连接
var client = new GLib.SocketClient ();
var connection = client.connect (
new GLib.NetworkAddress ("example.com", 80),
null
);
print ("已连接到 %s\n",
connection.get_remote_address ().to_string ());
// 发送 HTTP 请求
string request = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n";
connection.get_output_stream ().write (request.data);
// 读取响应
var data_stream = new GLib.DataInputStream (
connection.get_input_stream ()
);
string line;
size_t length;
int line_count = 0;
while ((line = data_stream.read_line (null, out length)) != null) {
print ("%s\n", line);
line_count++;
if (line_count > 20) break; // 只显示前 20 行
}
connection.close (null);
} catch (GLib.Error e) {
printerr ("网络错误: %s\n", e.message);
}
}
9.5.2 TCP 服务器
void main () {
try {
// 创建 TCP 服务器
var server = new GLib.SocketService ();
// 添加监听端口
server.add_inet_port (8080, null);
// 连接处理
server.incoming.connect ((connection, source) => {
handle_client.begin (connection);
return true;
});
print ("服务器监听端口 8080...\n");
// 运行主循环
var loop = new GLib.MainLoop ();
loop.run ();
} catch (GLib.Error e) {
printerr ("服务器错误: %s\n", e.message);
}
}
private async void handle_client (GLib.SocketConnection connection) {
try {
var addr = connection.get_remote_address ().to_string ();
print ("新连接: %s\n", addr);
var input = new GLib.DataInputStream (connection.get_input_stream ());
var output = connection.get_output_stream ();
// 发送欢迎消息
string welcome = "欢迎连接到 Vala 服务器!\n";
output.write (welcome.data);
// 读取客户端消息
string? line;
while ((line = yield input.read_line_async (
GLib.Priority.DEFAULT, null)) != null) {
print ("收到 [%s]: %s\n", addr, line);
// 回显
string response = "服务器收到: %s\n".printf (line);
output.write (response.data);
}
print ("断开连接: %s\n", addr);
connection.close (null);
} catch (GLib.Error e) {
printerr ("客户端错误: %s\n", e.message);
}
}
9.5.3 UDP 通信
void main () {
try {
// 创建 UDP Socket
var socket = new GLib.Socket (
GLib.SocketFamily.IPV4,
GLib.SocketType.DATAGRAM,
GLib.SocketProtocol.UDP
);
// 绑定地址
var addr = new GLib.InetSocketAddress (
new GLib.InetAddress.from_string ("0.0.0.0"),
9999
);
socket.bind (addr, true);
print ("UDP 服务器监听端口 9999...\n");
// 接收数据
uint8 buffer[1024];
GLib.SocketAddress sender_addr;
while (true) {
ssize_t received = socket.receive_from (
out sender_addr, buffer, null
);
if (received > 0) {
string message = (string) buffer;
message = message.substring (0, received);
print ("收到来自 %s: %s\n",
sender_addr.to_string (), message);
// 回复
string reply = "已收到: %s".printf (message);
socket.send_to (sender_addr, reply.data, null);
}
}
} catch (GLib.Error e) {
printerr ("UDP 错误: %s\n", e.message);
}
}
9.6 调用 C 库
9.6.1 使用 [CCode] 注解
// 绑定 C 函数
[CCode (cheader_filename = "math.h")]
namespace MathNative {
[CCode (cname = "sin")]
public static double sin (double x);
[CCode (cname = "cos")]
public static double cos (double x);
[CCode (cname = "sqrt")]
public static double sqrt (double x);
}
// 绑定自定义 C 函数
[CCode (cheader_filename = "mylib.h")]
namespace MyLib {
[CCode (cname = "my_function")]
public static int my_function (int x, int y);
}
void main () {
// 使用绑定的 C 函数
print ("sin(π/2) = %f\n", MathNative.sin (3.14159 / 2));
print ("cos(0) = %f\n", MathNative.cos (0));
print ("sqrt(16) = %f\n", MathNative.sqrt (16));
}
9.6.2 创建 VAPI 绑定文件
// mylib.vapi —— C 库的 Vala 绑定
[CCode (cheader_filename = "mylib.h")]
namespace MyLib {
// 函数绑定
[CCode (cname = "mylib_init")]
public static int init ();
[CCode (cname = "mylib_cleanup")]
public static void cleanup ();
// 结构体绑定
[CCode (cname = "MyLibConfig")]
public struct Config {
public string name;
public int version;
public bool debug;
}
// 回调绑定
[CCode (cname = "MyLibCallback", has_target = true)]
public delegate void Callback (string message);
// 枚举绑定
[CCode (cname = "MyLibStatus")]
public enum Status {
OK = 0,
ERROR = -1,
TIMEOUT = -2
}
}
9.6.3 调用系统命令
void main () {
// 使用 Posix 命名空间
print ("PID: %d\n", Posix.getpid ());
print ("UID: %d\n", Posix.getuid ());
print ("GID: %d\n", Posix.getgid ());
// 获取环境变量
string? home = GLib.Environment.get_variable ("HOME");
print ("HOME: %s\n", home);
string? path = GLib.Environment.get_variable ("PATH");
print ("PATH: %s\n", path ?? "未设置");
// 设置环境变量
GLib.Environment.set_variable ("MY_VAR", "hello", true);
print ("MY_VAR: %s\n", GLib.Environment.get_variable ("MY_VAR"));
// 获取系统信息
print ("主机名: %s\n", GLib.Environment.get_host_name ());
print ("用户名: %s\n", GLib.Environment.get_user_name ());
print ("用户目录: %s\n", GLib.Environment.get_home_dir ());
print ("临时目录: %s\n", GLib.Environment.get_tmp_dir ());
print ("当前目录: %s\n", GLib.Environment.get_current_dir ());
}
9.6.4 信号处理
void main () {
// 设置信号处理器
GLib.Unix.signal_add (Posix.Signal.INT, () => {
print ("\n收到 SIGINT (Ctrl+C)\n");
return GLib.Source.REMOVE;
});
GLib.Unix.signal_add (Posix.Signal.TERM, () => {
print ("\n收到 SIGTERM\n");
return GLib.Source.REMOVE;
});
GLib.Unix.signal_add (Posix.Signal.USR1, () => {
print ("\n收到 SIGUSR1\n");
return GLib.Source.CONTINUE;
});
print ("进程 PID: %d\n", Posix.getpid ());
print ("发送信号: kill -USR1 %d\n", Posix.getpid ());
print ("按 Ctrl+C 退出\n");
var loop = new GLib.MainLoop ();
loop.run ();
}
9.7 定时器和调度
void main () {
int count = 0;
// 定时器:每秒执行
GLib.Timeout.add (1000, () => {
count++;
print ("定时器触发: %d\n", count);
if (count >= 5) {
print ("定时器停止\n");
return GLib.Source.REMOVE; // 移除定时器
}
return GLib.Source.CONTINUE; // 继续
});
// Idle 回调:空闲时执行
uint idle_count = 0;
GLib.Idle.add (() => {
idle_count++;
if (idle_count > 100) {
return GLib.Source.REMOVE;
}
// 不要在这里做重活
return GLib.Source.CONTINUE;
});
// 延迟执行
GLib.Timeout.add_once (3000, () => {
print ("3 秒延迟执行\n");
});
var loop = new GLib.MainLoop ();
loop.run ();
}
9.8 业务场景:系统监控工具
// 系统信息结构
public class SystemInfo : Object {
public int cpu_usage { get; set; }
public int64 mem_total { get; set; }
public int64 mem_used { get; set; }
public int64 disk_total { get; set; }
public int64 disk_free { get; set; }
public double mem_usage_percent {
get {
if (mem_total == 0) return 0;
return (double) mem_used / mem_total * 100;
}
}
}
// 获取系统信息
public SystemInfo get_system_info () {
var info = new SystemInfo ();
// 读取内存信息
try {
string content;
GLib.FileUtils.get_contents ("/proc/meminfo", out content);
string[] lines = content.split ("\n");
foreach (string line in lines) {
if (line.has_prefix ("MemTotal:")) {
info.mem_total = parse_kb (line) * 1024;
} else if (line.has_prefix ("MemAvailable:")) {
int64 available = parse_kb (line) * 1024;
info.mem_used = info.mem_total - available;
}
}
} catch (GLib.Error e) {
printerr ("读取内存信息失败: %s\n", e.message);
}
// 读取磁盘信息
try {
int exit_status;
string std_out;
GLib.Process.spawn_command_line_sync (
"df -B1 / | tail -1",
out std_out, null, out exit_status
);
string[] parts = std_out.strip ().split_set (" \t");
if (parts.length >= 4) {
info.disk_total = int64.parse (parts[1]);
info.disk_free = int64.parse (parts[3]);
}
} catch (GLib.Error e) {
printerr ("读取磁盘信息失败: %s\n", e.message);
}
return info;
}
int64 parse_kb (string line) {
string[] parts = line.split_set (" \t");
foreach (string part in parts) {
if (part.length > 0 && part[0] >= '0' && part[0] <= '9') {
return int64.parse (part);
}
}
return 0;
}
string format_bytes (int64 bytes) {
if (bytes >= 1073741824) {
return "%.1f GB".printf ((double) bytes / 1073741824);
} else if (bytes >= 1048576) {
return "%.1f MB".printf ((double) bytes / 1048576);
}
return "%lld B".printf (bytes);
}
void print_bar (string label, double percent) {
int width = 30;
int filled = (int) (percent / 100 * width);
string bar = "";
for (int i = 0; i < width; i++) {
bar += i < filled ? "█" : "░";
}
print (" %s: [%s] %.1f%%\n", label, bar, percent);
}
void main () {
print ("=== 系统监控工具 ===\n\n");
// 定时刷新
GLib.Timeout.add (2000, () => {
var info = get_system_info ();
// 清屏
print ("\033[2J\033[H");
print ("=== 系统监控 ===\n");
print ("按 Ctrl+C 退出\n\n");
print_bar ("内存", info.mem_usage_percent);
print (" 内存: %s / %s\n\n",
format_bytes (info.mem_used),
format_bytes (info.mem_total));
double disk_percent = info.disk_total > 0
? (double) (info.disk_total - info.disk_free) / info.disk_total * 100
: 0;
print_bar ("磁盘", disk_percent);
print (" 磁盘: %s 可用 / %s 总计\n",
format_bytes (info.disk_free),
format_bytes (info.disk_total));
return GLib.Source.CONTINUE;
});
var loop = new GLib.MainLoop ();
GLib.Unix.signal_add (Posix.Signal.INT, () => {
loop.quit ();
return GLib.Source.REMOVE;
});
loop.run ();
}
9.9 注意事项
⚠️ 系统编程常见陷阱
- 线程安全:GTK 不是线程安全的,不要在非主线程操作 UI
- 文件描述符泄漏:确保关闭所有打开的文件描述符
- 竞态条件:使用互斥锁保护共享数据
- 信号处理:在信号处理器中只调用异步信号安全的函数
- 阻塞操作:不要在主线程执行阻塞的 I/O 操作
- 权限:某些操作需要 root 权限
9.10 扩展阅读
| 资源 | 链接 |
|---|---|
| GLib I/O | https://docs.gtk.org/gio/ |
| GLib 线程 | https://docs.gtk.org/glib/threads.html |
| GLib 网络 | https://docs.gtk.org/gio/networking.html |
| POSIX 手册 | man 7 posix |
| Unix 信号 | man 7 signal |
| Vala POSIX 绑定 | https://valadoc.org/posix.html |
9.11 总结
| 要点 | 说明 |
|---|---|
| 文件 I/O | 推荐使用 GLib.FileUtils / FileStream |
| 进程 | GLib.Process.spawn_* 或 GLib.Subprocess |
| 线程 | GLib.Thread + Mutex + Cond |
| 网络 | GLib.SocketClient / SocketService |
| C 绑定 | [CCode] 注解 + VAPI 文件 |
| 信号 | GLib.Unix.signal_add |
| 定时器 | GLib.Timeout.add / Idle.add |
下一章我们将学习 D-Bus 集成。→ 第 10 章:D-Bus 集成