线程安全问题
#include <stdio.h>
#include <tinycthread.h>
#include <io_utils.h>
int count = 0;
int Counter(void*arg)
{
for(int i = 0;i<100000;i++)
{
count++;
/*
* int temp = count;
* count=temp+1;
* return temp;
* */
}
return 0;
}
int main()
{
thrd_t t1;
thrd_t t2;
thrd_create(&t1,Counter,NULL);
thrd_create(&t2,Counter,NULL);
thrd_join(t1,NULL);
thrd_join(t2,NULL);
PRINT_INT(count);
return 0;
}
- 运行结果不是所要值原因是count++在并发时产生冲突
线程安全的产生
- 对共享资源进行非原子的访问
- 不同线程之间代码可见性问题
- 线程内部代码编译时的重排序问题
解决方法一 消除副作用
#include <stdio.h>
#include <tinycthread.h>
#include <io_utils.h>
int Counter(void*arg)
{
int count = 0;
for(int i = 0;i<100000;i++)
{
count++;
}
return count;
}
int main()
{
thrd_t t1;
thrd_t t2;
thrd_create(&t1,Counter,NULL);
thrd_create(&t2,Counter,NULL);
int count = 0;
int result = 0;
thrd_join(t1,&result);
count+=result;
thrd_join(t2,&result);
count+=result;
PRINT_INT(count);
return 0;
}
解决方法二 原子类型
#include<stdio.h>
#include <tinycthread.h>
#include <io_utils.h>
#include <stdatomic.h>
atomic_int count = 0; //设置原子类型
int Counter(void*arg)
{
for(int i = 0;i<100000;i++)
{
count++;
}
return 0;
}
int main()
{
thrd_t t1;
thrd_t t2;
thrd_create(&t1,Counter,NULL);
thrd_create(&t2,Counter,NULL);
thrd_join(t1,NULL);
thrd_join(t2,NULL);
PRINT_INT(count);
return 0;
}
解决方法三 原子操作
#include<stdio.h>
#include <tinycthread.h>
#include <io_utils.h>
#include <stdatomic.h>
atomic_flag resume_flag = ATOMIC_FLAG_INIT;
int PrintNumber(void*arg)
{
int current = 0;
while(atomic_flag_test_and_set(&resume_flag))
{
current++;
PRINT_INT(current);
thrd_sleep(&(struct timespec){.tv_sec=1},NULL);
}
return current;
}
int main()
{
atomic_flag_test_and_set(&resume_flag);
thrd_t t;
thrd_create(&t,PrintNumber,NULL);
thrd_sleep(&(struct timespec){.tv_sec=5},NULL);
atomic_flag_clear(&resume_flag);
int last_number = 0;
thrd_join(t,&last_number);
PRINT_INT(last_number);
return 0;
}
解决方法四 锁
#include <stdio.h>
#include <tinycthread.h>
#include <io_utils.h>
int count = 0;
mtx_t mutex;
int Counter(void*arg)
{
for(int i = 0;i<100000;i++)
{
mtx_lock(&mutex);
count++;
mtx_unlock(&mutex);
/*
* int temp = count;
* count=temp+1;
* return temp;
* */
}
return 0;
}
int main()
{
mtx_init(&mutex,mtx_plain);
thrd_t t1;
thrd_t t2;
thrd_create(&t1,Counter,NULL);
thrd_create(&t2,Counter,NULL);
thrd_join(t1,NULL);
thrd_join(t2,NULL);
PRINT_INT(count);
mtx_destroy(&mutex);
return 0;
}
解决方法五 线程存储期
#include <stdio.h>
#include <tinycthread.h>
#include <io_utils.h>
_Thread_local int count = 0;//每个线程都有一个独立的副本
int Counter(int* arg)
{
for(int i = 0;i<100000;i++)
{
count+=*arg;
/*
* int temp = count;
* count=temp+1;
* return temp;
* */
}
PRINT_INT(count);
return 0;
}
int main()
{
thrd_t t1;
thrd_t t2;
int arg_1 = 1;
int arg_2 = 2;
thrd_create(&t1,Counter,&arg_1);
thrd_create(&t2,Counter,&arg_2);
thrd_join(t1,NULL);
thrd_join(t2,NULL);
PRINT_INT(count);
return 0;
//count: 100000
//count: 200000
//count: 0
}
解决方法六 tss
#include <stdio.h>
#include <tinycthread.h>
#include <io_utils.h>
tss_t count_key;
void MyFree(void*ptr)
{
PRINTLNF("free %#x",ptr);
free(ptr);
}
int Counter(int* arg)
{
int* count = malloc(sizeof(int));
*count = 0;
if(tss_set(count_key,count) == thrd_success) //如果绑定成功
{
for (int i = 0; i < 100000; i++) {
*count += *arg;
/*
* int temp = count;
* count=temp+1;
* return temp;
* */
}
}
PRINT_INT(*count);
PRINT_INT(*((int*)tss_get(count_key)));
return 0;
}
int main()
{
if(tss_create(&count_key,MyFree)==thrd_success)
{
thrd_t t1;
thrd_t t2;
int arg_1 = 1;
int arg_2 = 2;
thrd_create(&t1,Counter,&arg_1);
thrd_create(&t2,Counter,&arg_2);
//tss_delete(count_key); 如果在线程结束前删除,则不会调用MyFree,需要自己手动释放内存。
thrd_join(t1,NULL);
thrd_join(t2,NULL);
puts("t_1,t_2 ends");
tss_delete(count_key);
PRINTLNF("count_key delete");
}
return 0;
}