C
GO

C to Go

10 lessons

Progress0%
1Variables & Types2Functions3Arrays & Slices4Structs & Methods5Pointers6Concurrency7Header Files → Packages8Error Handling9Testing10Standard Library
All Mirror Courses
C
GO
Concurrency
MirrorLesson 6 of 10
Lesson 6

Concurrency

Running multiple tasks concurrently

Introduction

In this lesson, you'll learn about concurrency in Go. Coming from C, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.

Mirror Card
C
From C:

In C, you're familiar with running multiple tasks concurrently.

GO
In Go:

Go has its own approach to running multiple tasks concurrently, which we'll explore step by step.

The Go Way

Let's see how Go handles this concept. Here's a typical example:

GO
Go Example
package main

import (
    "fmt"
    "sync"
)

func worker(id int, results chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    results <- id * 2
}

func main() {
    results := make(chan int, 5)
    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go worker(i, results, &wg)
    }

    // Close channel when all workers done
    go func() {
        wg.Wait()
        close(results)
    }()

    for r := range results {
        fmt.Println("result:", r)
    }
}

Comparing to C

Here's how you might have written similar code in C:

C
C (What you know)
#include <pthread.h>
#include <stdio.h>

typedef struct {
    int id;
    int result;
} WorkerArgs;

void *worker(void *arg) {
    WorkerArgs *w = (WorkerArgs *)arg;
    w->result = w->id * 2;
    return NULL;
}

int main() {
    pthread_t threads[5];
    WorkerArgs args[5];

    for (int i = 0; i < 5; i++) {
        args[i].id = i;
        pthread_create(&threads[i], NULL, worker, &args[i]);
    }
    for (int i = 0; i < 5; i++) {
        pthread_join(threads[i], NULL);
        printf("result[%d] = %d\n", i, args[i].result);
    }
}
Mirror Card
C
From C:

You may be used to different syntax or behavior.

GO
In Go:

Go goroutines are much lighter than pthreads (KB vs MB stack)

Mirror Card
C
From C:

You may be used to different syntax or behavior.

GO
In Go:

Go channels provide safe communication; C needs mutexes for shared memory

Mirror Card
C
From C:

You may be used to different syntax or behavior.

GO
In Go:

Go's go keyword is simpler than pthread_create

Mirror Card
C
From C:

You may be used to different syntax or behavior.

GO
In Go:

Go's select statement elegantly handles multiple channels; C has no equivalent

Step-by-Step Breakdown

1. Goroutines vs pthreads

A goroutine starts with just 'go func()'. Creating thousands of goroutines is normal; thousands of pthreads would exhaust OS resources.

C
C
pthread_create(&thread, NULL, worker, &args);
GO
Go
go worker(id, results, &wg)

2. Channels vs Shared Memory

Go's philosophy: 'Do not communicate by sharing memory; share memory by communicating.' Channels pass data safely between goroutines.

GO
Go
ch := make(chan int)
go func() { ch <- 42 }()
val := <-ch

3. sync.WaitGroup vs pthread_join

WaitGroup tracks when all goroutines finish, equivalent to joining all threads but without needing thread IDs.

C
C
pthread_join(thread, NULL);
GO
Go
wg.Add(1); go func() { defer wg.Done(); work() }()
wg.Wait()

Common Mistakes

When coming from C, developers often make these mistakes:

  • Go goroutines are much lighter than pthreads (KB vs MB stack)
  • Go channels provide safe communication; C needs mutexes for shared memory
  • Go's go keyword is simpler than pthread_create
Common Pitfall
Don't assume Go works exactly like C. While the concepts may be similar, the syntax and behavior can differ significantly.

Key Takeaways

  • go keyword replaces pthread_create
  • Channels replace shared memory + mutexes for communication
  • sync.WaitGroup replaces pthread_join
  • Goroutines are far lighter than OS threads
Rule of Thumb
The best way to learn is by doing. Try rewriting some of your C code in Go to practice these concepts.
PreviousNext