How to start streams in plain C?

I used fork () in C to start another process. How to start a new thread?

+48
c multithreading
Sep 11 '08 at 15:04
source share
6 answers

Since you mentioned fork (), I assume that you are using a Unix-like system, in which case POSIX threads (commonly called pthreads) are what you want to use.

In particular, pthread_create () is the function needed to create a new thread. His arguments are:

int pthread_create(pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg); 

The first argument is the return pointer to the stream identifier. The second argument is the stream arguments, which can be NULL if you do not want to start the stream with a specific priority. The third argument is the function executed by the thread. The fourth argument is the only argument passed to the stream function when it is executed.

+52
Sep 11 '08 at 15:09
source share

AFAIK, ANSI C does not define streams, but various libraries exist.

If you are running Windows, connect to msvcrt and use _beginthread or _beginthreadex.

If you work on other platforms, check out the pthreads library (I'm sure there are others).

+12
Sep 11 '08 at 15:10
source share

Threads are not part of the C standard, so the only way to use threads is to use some library (for example: POSIX threads on Unix / Linux, _beginthread / _beginthreadex, if you want to use C-runtime from this thread or just CreateThread Win32 API)

+8
Sep 11 '08 at 16:03
source share

pthreads is a good start, look here

+7
Sep 11 '08 at 15:08
source share

Take a look at pthread (POSIX thread library).

+2
Sep 11 '08 at 15:08
source share

Thread C11 + C11 atomic_int

Added in glibc 2.28. Tested on Ubuntu 18.10 amd64 (ships with glic 2.28) and Ubuntu 18.04 (ships with glibc 2.27) by compiling glibc 2.28 from source: Multiple glibc libraries on the same host

Example adapted from: https://en.cppreference.com/w/c/language/atomic

main.c

 #include <stdio.h> #include <threads.h> #include <stdatomic.h> atomic_int atomic_counter; int non_atomic_counter; int mythread(void* thr_data) { (void)thr_data; for(int n = 0; n < 1000; ++n) { ++non_atomic_counter; ++atomic_counter; // for this example, relaxed memory order is sufficient, eg // atomic_fetch_add_explicit(&atomic_counter, 1, memory_order_relaxed); } return 0; } int main(void) { thrd_t thr[10]; for(int n = 0; n < 10; ++n) thrd_create(&thr[n], mythread, NULL); for(int n = 0; n < 10; ++n) thrd_join(thr[n], NULL); printf("atomic %d\n", atomic_counter); printf("non-atomic %d\n", non_atomic_counter); } 

Github upstream .

Compile and run:

 gcc -ggdb3 -std=c11 -Wall -Wextra -pedantic -o main.out main.c -pthread ./main.out 

Possible conclusion:

 atomic 10000 non-atomic 4341 

Most likely, the non-atomic counter will be smaller than the atomic counter due to quick access through flows to the non-atomic variable.

See also: How to make atomic increment and extract in C?

Disassembly analysis

Disassemble with:

 gdb -batch -ex "disassemble/rs mythread" main.out 

contains:

 17 ++non_atomic_counter; 0x00000000004007e8 <+8>: 83 05 65 08 20 00 01 addl $0x1,0x200865(%rip) # 0x601054 <non_atomic_counter> 18 __atomic_fetch_add(&atomic_counter, 1, __ATOMIC_SEQ_CST); 0x00000000004007ef <+15>: f0 83 05 61 08 20 00 01 lock addl $0x1,0x200861(%rip) # 0x601058 <atomic_counter> 

therefore, we see that the atomic increment is executed at the instruction level with the lock prefix f0 .

With aarch64-linux-gnu-gcc 8.2.0 we get instead:

 11 ++non_atomic_counter; 0x0000000000000a28 <+24>: 60 00 40 b9 ldr w0, [x3] 0x0000000000000a2c <+28>: 00 04 00 11 add w0, w0, #0x1 0x0000000000000a30 <+32>: 60 00 00 b9 str w0, [x3] 12 ++atomic_counter; 0x0000000000000a34 <+36>: 40 fc 5f 88 ldaxr w0, [x2] 0x0000000000000a38 <+40>: 00 04 00 11 add w0, w0, #0x1 0x0000000000000a3c <+44>: 40 fc 04 88 stlxr w4, w0, [x2] 0x0000000000000a40 <+48>: a4 ff ff 35 cbnz w4, 0xa34 <mythread+36> 

therefore, the atomic version actually has a cbnz loop that runs until the stlxr repository is successful.

Benchmark

DO. Create a benchmark to show that atomic is slower.

POSIX Themes

main.c

 #define _XOPEN_SOURCE 700 #include <assert.h> #include <stdlib.h> #include <pthread.h> enum CONSTANTS { NUM_THREADS = 1000, NUM_ITERS = 1000 }; int global = 0; int fail = 0; pthread_mutex_t main_thread_mutex = PTHREAD_MUTEX_INITIALIZER; void* main_thread(void *arg) { int i; for (i = 0; i < NUM_ITERS; ++i) { if (!fail) pthread_mutex_lock(&main_thread_mutex); global++; if (!fail) pthread_mutex_unlock(&main_thread_mutex); } return NULL; } int main(int argc, char **argv) { pthread_t threads[NUM_THREADS]; int i; fail = argc > 1; for (i = 0; i < NUM_THREADS; ++i) pthread_create(&threads[i], NULL, main_thread, NULL); for (i = 0; i < NUM_THREADS; ++i) pthread_join(threads[i], NULL); assert(global == NUM_THREADS * NUM_ITERS); return EXIT_SUCCESS; } 

Compile and run:

 gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.c -pthread ./main.out ./main.out 1 

The first run works fine, the second fails due to lack of synchronization.

POSIX Standardized Atomic Operations Does Not Appear: Portable UNIX Atomic Operations

Tested on Ubuntu 18.04. Github upstream .

GCC __atomic_* Built-in Modules

For those who do not have C11, you can achieve atomic increments with __atomic_* GCC extensions.

main.c

 #define _XOPEN_SOURCE 700 #include <pthread.h> #include <stdatomic.h> #include <stdio.h> #include <stdlib.h> enum Constants { NUM_THREADS = 1000, }; int atomic_counter; int non_atomic_counter; void* mythread(void *arg) { (void)arg; for (int n = 0; n < 1000; ++n) { ++non_atomic_counter; __atomic_fetch_add(&atomic_counter, 1, __ATOMIC_SEQ_CST); } return NULL; } int main(void) { int i; pthread_t threads[NUM_THREADS]; for (i = 0; i < NUM_THREADS; ++i) pthread_create(&threads[i], NULL, mythread, NULL); for (i = 0; i < NUM_THREADS; ++i) pthread_join(threads[i], NULL); printf("atomic %d\n", atomic_counter); printf("non-atomic %d\n", non_atomic_counter); } 

Compile and run:

 gcc -ggdb3 -O3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c -pthread ./main.out 

Output and generated assembly: the same as in the example with "C11 threads".

Tested on Ubuntu 16.04 amd64, GCC 6.4.0.

+2
Sep 22 '18 at 3:40
source share



All Articles