You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Go/C中以编程方式实现类似cgexec的进程控制组功能?

Implementing cgexec-like Functionality in C and Go (Idiomatic Approaches)

Great question! Using raw exec calls can feel pretty clunky when you want to replicate cgexec's behavior—especially if you're aiming for code that's clean, maintainable, and fits with each language's idioms. Let's walk through better approaches for both C and Go.

For C: Use libcgroup for Abstracted, Clean Control

Instead of manually forking, writing to cgroup filesystem paths, and calling execve (which is error-prone and messy), leverage the libcgroup library—it provides a high-level API for managing cgroups, making your code far more idiomatic and robust.

Here's a quick example that runs a command inside a target cgroup:

#include <libcgroup.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    struct cgroup *cg;
    int ret;

    // Initialize libcgroup
    if (cgroup_init() != 0) {
        perror("Failed to initialize libcgroup");
        return EXIT_FAILURE;
    }

    // Load the target cgroup (e.g., "mycgroup" under cpu controller)
    cg = cgroup_new_cgroup("cpu/mycgroup");
    if (!cg) {
        perror("Failed to create cgroup handle");
        return EXIT_FAILURE;
    }

    // Execute the command inside the cgroup
    // argv[1] is the command to run, argv[2...] are arguments
    ret = cgroup_execute_command(cg, argc - 1, &argv[1], NULL);
    if (ret != 0) {
        fprintf(stderr, "Failed to run command in cgroup: %s\n", cgroup_strerror(ret));
        cgroup_free(&cg);
        return EXIT_FAILURE;
    }

    cgroup_free(&cg);
    return EXIT_SUCCESS;
}

This approach is way cleaner than manual filesystem operations:

  • It handles cgroup validation and error checking out of the box
  • You avoid typos or permission issues with direct /sys/fs/cgroup writes
  • The API aligns with standard C library patterns, making your code easier for other C devs to follow

If you need more control (like forking a child process and attaching it to a cgroup without replacing the parent), use cgroup_fork() followed by cgroup_attach_task()—this mimics the fork-style behavior you're looking for.

For Go: Encapsulate Cgroup Logic in Idiomatic Structures

Go's os/exec is functional, but wrapping it in a reusable, Go-style abstraction makes it feel far more elegant. Instead of scattering cgroup filesystem writes around your code, encapsulate the logic in a struct with methods—this fits Go's emphasis on composition and readability.

Here's an example using only standard library calls (no third-party dependencies):

package main

import (
	"os"
	"os/exec"
	"strconv"
	"syscall"
)

// Cgroup represents a control group we want to run processes in
type Cgroup struct {
	Path string // e.g., "/sys/fs/cgroup/cpu/mycgroup"
}

// NewCgroup creates a new Cgroup instance
func NewCgroup(path string) *Cgroup {
	return &Cgroup{Path: path}
}

// Run starts a command inside the cgroup
func (cg *Cgroup) Run(cmd string, args ...string) error {
	// Prepare the command
	command := exec.Command(cmd, args...)
	command.Stdout = os.Stdout
	command.Stderr = os.Stderr

	// Set up a callback to attach the process to the cgroup after forking
	command.SysProcAttr = &syscall.SysProcAttr{
		Setpgid: true,
		Pdeathsig: syscall.SIGKILL, // Optional: kill child if parent dies
	}

	// Start the command
	if err := command.Start(); err != nil {
		return err
	}

	// Write the child PID to the cgroup's tasks file
	pidStr := strconv.Itoa(command.Process.Pid)
	tasksPath := cg.Path + "/tasks"
	if err := os.WriteFile(tasksPath, []byte(pidStr), 0644); err != nil {
		// If attaching fails, clean up the child process
		_ = command.Process.Kill()
		return err
	}

	// Wait for the command to finish
	return command.Wait()
}

func main() {
	cg := NewCgroup("/sys/fs/cgroup/cpu/mycgroup")
	if err := cg.Run("sleep", "10"); err != nil {
		panic(err)
	}
}

This is far more idiomatic than raw exec calls because:

  • It encapsulates cgroup logic in a reusable Cgroup type, making your code modular
  • It uses Go's method syntax to create a clean, intuitive API (cg.Run(...))
  • It handles cleanup (killing the child if cgroup attachment fails) which raw exec wouldn't do automatically

If you want even more abstraction (e.g., creating cgroups on the fly, managing multiple controllers), you could use a well-maintained third-party library focused on cgroup management, but the above example keeps it lightweight with standard library code.


内容的提问来源于stack exchange,提问作者nanogru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:45:04