github contributed by <Diana Ho
>
d0651
sys
sort -R
่็้็บไบๅ้ ๅทฅไฝ๏ผๅจ worker thread ๅฏฆไฝ Task ็ๆฉๅถใๆฏๅไธป่ฆ็ๆไฝๆๅ ่ขซๆพ้ฒ task queue ่ฃก้ ญ๏ผ็ฉบ้็ thread ๅๅพ task queue ่ฃก้ ญๆๅ task ๅท่ก๏ผๅช่ฆๆๆๅ็ๆไฝๅฏซๆ task๏ผๅฐฑ่ฝ้ ๅฉๅท่กใ
pthread_join๏ผ ๆๅท่ก็ทๆซๅๅท่ก็ดๅฐๅฆไธ็ด่ก็ท็ตๆ
Mutex๏ผ ๅไธๆ้ๅ งๅชๆไธๅท่ก็ทๅฏไปฅไฟๆ่ฉฒ lock ๅไฟ่ญท่ณๆ็ๅญๅๆฌ
PTHREAD_MUTEX_INITIALIZER
pthread_mutex_init()
pthread_mutex_lock()
pthread_mutex_unlock()
Condition variable๏ผ ๅฐไบไปถๅฏฆ่ณชๅ๏ผไธฆๆไพๅฝๅผๅ้็ญๅพ ่ฉฒไบไปถ็ๅท่ก็ท
PTHREAD_COND_INITIALIZER
pthread_cond_init()
pthread_cond_wait()
pthread_cond_timewait()
pthread_cond_signal()
pthread_cond_broadcast()
pthread_once๏ผ ไฟ่ญๅๅงๅฝๅผ่ขซ่จฑๅค็ด่ก็ทๅผๅซๆๅ ๅท่กไธๆฌก
PTHREAD_ONCE_INIT
ไธ็จฎๆๆจ๏ผๅฐ่ณๆๅๅท่ก็ท้ฒ่ก้่ฏ
PTHREAD_CANCEL_DISABLE
PTHREAD_CANCEL_ENABLE
PTHREAD_CANCEL_ASYNCHRONOUS
๏ผ็ซๅปๅๆถPTHREAD_CANCEL_DEFERRED
๏ผ็ถๅท่กๅฐ Cancellation-point ๆ็ผ็pthread_cond_wait(), pthread_cond_timewait(), pthread_join()
pthread_testcancel()
mutrace ๅฏ็จไพๅตๆธฌ lock contention๏ผไฝฟ็จๆนไพฟ๏ผไธ้่ฆ้ๆฐ็ทจ่ญฏ็จๅผ็ขผใ
Lock contention: this occurs whenever one process or thread attempts to acquire a lock held by another process or thread. The more fine-grained the available locks, the less likely one process/thread will request a lock held by the other. (For example, locking a row rather than the entire table, or locking a cell rather than the entire row.)
mutrace v.s. valgrind/drd
In contrast to valgrind/drd it does not virtualize the CPU instruction set, making it a lot faster. In fact, the hooks mutrace relies on to profile mutex operations should only minimally influence application runtime. Mutrace is not useful for finding synchronizations bugs, it is solely useful for profiling locks.
About mutrace
-rdynamic
to make the backtraces mutrace generates useful.-r
| โtrack-rt: checks on each mutex operation wheter it is executed by a realtime thread or not.matrace
that can be used to track down memory allocation operations in realtime threads.
typedef struct node {
val_t data;
struct node *next;
} node_t;
typedef struct llist {
node_t *head;
uint32_t size;
} llist_t;
When/Why to use intptr_t for type-casting in C?
What is the use of intptr_t?
void *
๏ผintptr_t
็ไฝๅๅฏไปฅๅ bitwise operation ่ void *
ไธ่ฝใๅไฝๅ
้็ฎ๏ผ็ก่็uintptr_t
ๆๆฏ่ผๅฅฝใ
โโโโ/* Types for `void *' pointers. */
โโโโ#if __WORDSIZE == 64
โโโโ# ifndef __intptr_t_defined
โโโโtypedef long int intptr_t;
โโโโ# define __intptr_t_defined
โโโโ# endif
โโโโtypedef unsigned long int uintptr_t;
โโโโ#else
โโโโ# ifndef __intptr_t_defined
โโโโtypedef int intptr_t;
โโโโ# define __intptr_t_defined
โโโโ# endif
โโโโtypedef unsigned int uintptr_t;
โโโโ#endif
intptr_t
๏ผๅพๅพๆๅๅช้ #include <stdint>
ๅฐฑ่ฝๅ
้ค้บป็
ฉ็ๅๆ
่ฝๆใ้คๆญคไนๅค๏ผไนๆฏ็ขบไฟๅๆ
่ฝๆไธไธๆๅบๅ้ก็ไฟๅฎไฝๆณใ
โ#ifdef MACHINE 64
โ typedef long intptr;
โ#else // MACHINE 32
โ typedef int intptr;
โ#endif
typedef struct _task {
void (*func)(void *);
void *arg;
struct _task *next, *last;
} task_t;
typedef struct {
task_t *head, *tail;
pthread_mutex_t mutex;
pthread_cond_t cond;
uint32_t size;
} tqueue_t;
typedef struct {
pthread_t *threads;
uint32_t count;
tqueue_t *queue;
} tpool_t;
merge_list()
ๅณๅ
ฅๅ
ฉๅlist๏ผ็ถๅพๅปๆฏ่ผ2ๅlistๆๅฐ็้ฃๅๅไธไธๆๅบ๏ผๆพๅฐๆฐ็list่ฃก้ข๏ผ็ดๅฐๅ
ถไธญไธๅlist็ๆธ่ขซๆๅฎ๏ผ้ๆๆธๅญ็listๅฐฑๆฅๅฐๅทฒๆๅบๅฅฝ็listๅพ้ขใmerge_sort()
ๅฆๆๅณๅ
ฅ็list sizeๅฐๆผ2็ดๆฅๅๅณ่ฉฒlist๏ผๅฆๅๅฐฑๅฐไปๅพไธญ้ๅๆ2ๅlistไนๅพไธ้ฒ merge_list()
ๅๆๅบไธฆๅๅณๆๅบๅฅฝ็listใmerge
่ฃก้ขๅปๅคๆท็พๅจ็list็ธฝๅ
ฑไธฒไบๅนพๅ๏ผๅฆๆๅฐๆผ่ผธๅ
ฅ็่ณๆๆธ๏ผๅฐฑ็นผ็บๅๆๅบไธฒ่ตทไพ๏ผไธ็ถๅฐฑ่จญ็ฝฎ็ตๆญขtask็ถๅพๅฐๅบๆๅบๅฅฝ็listใtask_run
ๅฐๆๅ่ฆๅ็ไบๅฏซๆtask๏ผๆพ้ฒjob queue่ฃก๏ผ็ฉบ้็threadๆๅพqueue่ฃกๆฟtaskๅบไพๅใ -M
็ๆๆไปถ้่ฏ็ไฟกๆฏใๅ
ๅซ็ฎๆจๆไปถๆไพ่ณด็ๆๆๆบไปฃ็ขผ
-MM
ๅ-Mไธๆจฃ๏ผไฝๆฏๅฎๅฐๅฟฝ็ฅ็ฑ#include<file>;้ ๆ็ไพ่ณด้ไฟใ
-MD
ๅ-M็ธๅ๏ผไฝๆฏ่ผธๅบๅฐๅฐๅ
ฅๅฐ.d็ๆไปถ่ฃก้ข
-MMD
ๅ-MM็ธๅ๏ผไฝๆฏ่ผธๅบๅฐๅฐๅ
ฅๅฐ.d็ๆไปถ่ฃก้ข
-MF
ๆๅฎ่ผธๅบๅฐๆๅๆชๆก,ๅฆๅ้ ่จญๆฏๅๅงๆชๆกๆชๅ.d
-rdynamic๏ผ
ๆๅฎ linker ๅฐๆๆ label ๅฏซๅ
ฅๅฐ dynamic symbol tableใ
$ (for i in {1..8}; do echo $RANDOM; done) | mutrace ./sort 4 8
mutrace: 0.2 sucessfully initialized for process sort (pid 11679).
input unsorted data line-by-line
sorted results:
[300] [2022] [6225] [10989] [17303] [23622] [32251] [32551]
mutrace: Showing statistics for process sort (pid 11679).
mutrace: 3 mutexes used.
mutrace: Showing 3 most contended mutexes:
Mutex # Locked Changed Cont. tot.Time[ms] avg.Time[ms] max.Time[ms] Flags
0 145 40 30 0.023 0.000 0.001 Mx.--.
1 13 10 1 0.002 0.000 0.000 M-.--.
2 20 3 0 0.006 0.000 0.001 M-.--.
||||||
/|||||
Object: M = Mutex, W = RWLock /||||
State: x = dead, ! = inconsistent /|||
Use: R = used in realtime thread /||
Mutex Type: r = RECURSIVE, e = ERRRORCHECK, a = ADAPTIVE /|
Mutex Protocol: i = INHERIT, p = PROTECT /
RWLock Kind: r = PREFER_READER, w = PREFER_WRITER, W = PREFER_WRITER_NONREC
mutrace: Note that the flags column R is only valid in --track-rt mode!
mutrace: Total runtime is 0.883 ms.
mutrace: Results for SMP with 8 processors.
Locked
: how often the mutex was locked during the entire runtime.Changed
: how often the owning thread of the mutex changed.Cont.
: how often the lock was already taken when we tried to take it and we had to wait.tot.Time[ms]
: for how long during the entire runtime the lock was lockedavg.Time[ms]
: the average lock timemax.Time[ms]
: the longest time the lock was held.Flags
: what kind of mutex this is (recursive, normal or otherwise).ๆ็
งไฝๆฅญ่ฆๆฑไธญๆๆ็ไฝฟ็จ addr2line
ๆพๅฐๅฏฆ้ๅฐๆ็็จๅผ่กๆธ๏ผๅป้กฏ็คบ ??:0
๏ผ ็ฎๅ้ๅจๅฐๆพๅๅ
$ addr2line -e sort 0x38
??:0
ๅฐ phonebook-concurrent ่ฃก็ dictionary/words.txt
้้ UNIX ๆไปคๆไบ้ ๅบ๏ผไนๅพ้ๆฐๅฐๅๅฐๅฆไธๅๆชๆก input.txt
๏ผ่ฎๆmerge sortๆฐ็่ณๆ่ผธๅ
ฅ
$ uniq words.txt | sort -R > input.txt
sort
๏ผๅฐ่ผธๅ
ฅ่ณๆๆๅบ
-R
flag๏ผ้จๆฉๆๅบuniq
๏ผๅฏไปฅ็จไพๅฐ้่ค็่กๅช้ค่ๅช้กฏ็คบไธๅ
-c
flag๏ผ้กฏ็คบ้่คๅญ่ฉ็ๅบ็พๆฌกๆธwc
๏ผๅๅบๆชๆกๆๅคๅฐ่ก๏ผๅคๅฐๅฎๅญ๏ผๅคๅฐๅญๅ
-l/w/m
๏ผๅ
ๅๅบ่กใๅฎๅญใๅญๅ
llist
ๆๆจ๏ผไฝฟ็จๆดๅฝๆงใ
โโโโโโโโllist_t list_add(llist_t *list, val_t val)
โโโโโโโโ{
โโโโโโโโ //check if value already exist
โโโโโโโโ node_t *cur = list->head;
โโโโโโโโ while(cur) {
โโโโโโโโ if(cur-> data == val) return list;
โโโโโโโโ cur = cur->next;
โโโโโโโโ }
โโโโโโโโ //add to the head of the list
โโโโโโโโ node_t *e = node_new(val, NULL);
โโโโโโโโ e->next = list->head;
โโโโโโโโ list->head = e;
โโโโโโโโ list->size++;
โโโโโโโโ return list;
โโโโโโโโ}
if(idx > list->size-1)
if(idx == 0) return cur;
โโโโโโโโnode_t *list_nth(llist_t *list, uint32_t idx)
โโโโโโโโ{
โโโโโโโโ if (idx > list->size-1)
โโโโโโโโ return NULL;
โโโโโโโโ node_t *head = list->head;
โโโโโโโโ if(idx == 0)
โโโโโโโโ return head;
โโโโโโโโ while (idx--)
โโโโโโโโ head = head->next;
โโโโโโโโ return head;
โโโโโโโโ}
tqueue_t
็่จๆถ้ซ็ฉบ้้
็ฝฎ
โโโโโโโโint tqueue_init(tqueue_t *the_queue)
โโโโโโโโ{
โโโโโโโโ // if((the_queue = (tqueue_t *)malloc(sizeof(tqueue_t)) )== NULL)
โโโโโโโโ // return -1;
โโโโโโโโ the_queue->head = NULL;
โโโโโโโโ the_queue->tail = NULL;
โโโโโโโโ pthread_mutex_init(&(the_queue->mutex), NULL);
โโโโโโโโ pthread_cond_init(&(the_queue->cond), NULL);
โโโโโโโโ the_queue->size = 0;
โโโโโโโโ return 0;
โโโโโโโโ}
if((the_queue = (tqueue_t *)malloc(sizeof(tqueue_t)) )== NULL) return -1;
่จป่งฃๆ๏ผๆไธๆ็ผ็ segmentation fault(core dumped)tail
ๆนๆ head
โโโโโโโโtask_t *tqueue_pop(tqueue_t *the_queue)
โโโโโโโโ{
โโโโโโโโ task_t *ret;
โโโโโโโโ pthread_mutex_lock(&(the_queue->mutex));
โโโโโโโโ ret = the_queue->head;
โโโโโโโโ if (ret) {
โโโโโโโโ the_queue->head = ret->next;
โโโโโโโโ if (the_queue->head) {
โโโโโโโโ the_queue->head->last = NULL;
โโโโโโโโ } else {
โโโโโโโโ the_queue->tail = NULL;
โโโโโโโโ }
โโโโโโโโ the_queue->size--;
โโโโโโโโ }
โโโโโโโโ pthread_mutex_unlock(&(the_queue->mutex));
โโโโโโโโ return ret;
โโโโโโโโ}
head
ๆน็บ tail
โโโโโโโโint tqueue_push(tqueue_t *the_queue, task_t *task)
โโโโโโโโ{
โโโโโโโโ if(task == NULL) return -1;
โโโโโโโโ pthread_mutex_lock(&(the_queue->mutex));
โโโโโโโโ task->next = NULL;
โโโโโโโโ task->last = the_queue->tail;
โโโโโโโโ if (the_queue->tail)
โโโโโโโโ the_queue->tail->next = task;
โโโโโโโโ the_queue->tail = task;
โโโโโโโโ if (the_queue->size++ == 0)
โโโโโโโโ the_queue->head = task;
โโโโโโโโ pthread_mutex_unlock(&(the_queue->mutex));
โโโโโโโโ return 0;
โโโโโโโโ}
the_queue
ๆฏๅฆๅญๅจ็ๆ
ๆณ๏ผๅฆๅๅๅณ -1๏ผไธฆไธไธๅจๅท่กไธ้ข้ๆพ่จๆถ้ซ้จๅthread_cond_detroy(&(the_queue->cond));
โโโโโโโโint tqueue_free(tqueue_t *the_queue)
โโโโโโโโ{
โโโโโโโโ if(the_queue == NULL) return -1;
โโโโโโโโ task_t *cur = the_queue->head;
โโโโโโโโ while (cur) {
โโโโโโโโ the_queue->head = the_queue->head->next;
โโโโโโโโ free(cur);
โโโโโโโโ cur = the_queue->head;
โโโโโโโโ }
โโโโโโโโ pthread_mutex_destroy(&(the_queue->mutex));
โโโโโโโโ pthread_cond_destroy(&(the_queue->cond));
โโโโโโโโ return 0;
โโโโโโโโ}
the_pool
ๆฏๅฆๅญๅจ็ๅคๆท๏ผไปฅๅpthread_join()
ๆฏๅฆๆๅ็ๅคๆท
โโโโโโโโint tpool_free(tpool_t *the_pool)
โโโโโโโโ{
โโโโโโโโ if(the_pool == NULL) return -1;
โโโโโโโโ for (uint32_t i = 0; i < the_pool->count; ++i)
โโโโโโโโ if(pthread_join(the_pool->threads[i], NULL) != 0) return -1;
โโโโโโโโ free(the_pool->threads);
โโโโโโโโ tqueue_free(the_pool->queue);
โโโโโโโโ return 0;
โโโโโโโโ}
concurrent-ll
lock-free
ๅจ Makefile ไธญๅ ๅ ฅ่ฆๅ๏ผๅฉ็จ็ณป็ตฑๅ งๅปบ็ๅทฅๅ ทไพ้จๆฉ็ข็่ณๆไปฅๅๆฏ่ผ็ตๆใ
check: all
sort -R words.txt | ./sort $(THREAD_NUM) $(shell wc -l words.txt) > sorted.txt
diff -u words.txt sorted.txt && echo "Verified!" || echo "Failed!"