Какой самый простой способ передачи данных между встроенной структурой c? - PullRequest
0 голосов
/ 17 февраля 2020

У меня есть две структуры

//Pseudo code
type task struct {}
type tasks struct []{
     t task 
}

Я хочу запустить одну задачу и после ее завершения передать информацию задачам: например, после завершения task1 и task2, уведомить tasks, а затем запустить task3. Таким образом, этот task.finished() должен уведомить tasks. и tasks, что он должен убедиться, что оба task1 и task2 завершили, чтобы вызвать задачу 3.

 //Pseudo code    
 task1.start() and task2.start() at the same time

 if  task1.finished() && task2.finished():
     task3.run()

Что самое идиоматическое c способ передачи данных между встроенными структурами?

Я понимаю, что такие логики c должны выполняться в tasks, но как task1 и task2 сообщают tasks, что они закончены?

Должен ли я ввести новую структуру, которая хранит информацию, необходимую для обмена, под названием "taskManager"?

1 Ответ

1 голос
/ 17 февраля 2020
type tasks []*task

type task struct {
    Data       int
    onComplete chan struct{}
}

var wg sync.WaitGroup

// each task will in one goroutine
// pointer receiver
func (t *task) Run() {
    defer wg.Done()

    sleepTime := time.Second * time.Duration(t.Data)

    fmt.Println("Task:", t.Data, "sleeping for", sleepTime)
    time.Sleep(sleepTime)

    fmt.Println("Task:", t.Data, "done")

    // Once work is done, Inform, if we have to
    if t.onComplete != nil {
        t.onComplete <- struct{}{}
    }
}

// Run given tasks
func Run(ts tasks) {
    wg.Add(len(ts))

    for _, t := range ts {
        // run each task in seperate goroutines
        go t.Run()
    }
}

func (ts tasks) OnComplete(pending tasks) {
    tempChan := make(chan struct{})

    // all tasks should inform to `tempChan`,
    // once done
    for _, t := range ts {
        t.onComplete = tempChan
    }

    tasksNum := len(ts)

    wg.Add(1)
    go func() {
        // once we receive enough signals
        // i.e., once all `ts` tasks are done run pending tasks
        for range tempChan {
            tasksNum--
            if tasksNum == 0 {
                Run(pending)
                close(tempChan)
            }
        }
        wg.Done()
    }()
}

func main() {

    // define tasks
    mainTasks := tasks{
        {Data: 1},
        {Data: 2},
    }

    // tasks which need to run once certain tasks were done
    pendingTasks := tasks{
        {Data: 3},
    }

    // Inform to run pending tasks once mainTasks are done
    mainTasks.OnComplete(pendingTasks)

    // start runing your main tasks
    Run(mainTasks)

    wg.Wait()
}

Go PlayGround

Фактически вы можете продолжать цепочку работ, если бы pendingTasks.OnComplete(someMoreTasks)

Затем выполните mainTasks, один раз done выполнит PendingTasks, как только будет выполнено someMoreTasks.

Возможны и другие виды сложных отношений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...