源文件中导入pthread.h包
因为在Linux中pthread线程库是需要链接的所以在编译的时候需要加上-lpthread
总体输入格式如下
gcc Threads.c -lpthread -o Threads
初步实现多线程
#include <stdio.h>
#include <pthread.h>
#define THREAD_COUNT 20
void *thread_callback(void *arg)
{
int *count = (int *)arg;
int i = 0;
while (i++ <100000)
{
(*count) ++;
usleep(1); // 进程休眠1微秒
}
}
int main()
{
pthread_t threadid[THREAD_COUNT] = {0}; //定义线程数组 长度为宏定义的20 每个元素都是 pthread_t 类型的变量,{0}是初始化为0
int i = 0;
int count = 0;
//创建10个线程
for (i = 0 ;i< THREAD_COUNT;i++)
{
//创建线程 并共用count参数
pthread_create(&threadid[i],NULL,thread_callback,&count);
}
for(i = 0 ; i<100;i++)
{
printf("count: %d \n" , count);
sleep(1);
}
}
互斥锁 在大型临界区或者多核CPU情况下,建议使用互斥锁。
//创建互斥锁
pthread_metux_t xxxx;
//初始化互斥锁
pthread_metux_init (&xxxx,null);
在理想状态下 线程1 执行完在执行线程2
但事实上 在执行线程1的过程中(未执行完线程1的指令) 插入线程2的指令 导致程序同一个数重复执行
老师的图解
![](https://img-blog.csdnimg.cn/0851def1a757438e9debe4b849dbc97c.png)
因为 count是一个线程共用的临界资源所以需要对其加锁 使得在线程1调用count的时候线程2无法调用 效果类似于sql的锁 在调用前加锁 调用完成后解锁
自旋锁 通常用于小型临界资源
//创建自旋锁
pthread_spinlock_t xxxx;
//初始化互斥锁
pthread_spinlock_init (&xxxx,PTHREAD_PROCESS_SHARED);
类似于while(1); 从A进程进入锁中 B进程进不去就会一直等待锁解锁 直到A进程执行完毕
获取自旋锁时,如果发现自旋锁已经被其他线程持有,则当前线程会一直处于忙等状态,直到自旋锁被释放为止。因为自旋锁不涉及内核态切换,所以相较于互斥锁而言,可以避免系统调用的开销,在保护小型临界区时效率更高。
原子操作 把线程1的多条操作合并成一条 就可以避免执行过程中 被B进程突进 从而不使用锁
注:也就是单条cpu指令的实现 也是一种锁但是比互斥锁和自旋锁更好
#include <stdio.h>
#include <pthread.h>
#define THREAD_COUNT 10
pthread_mutex_t mutex; //定义一把互斥锁
pthread_spinlock_t spinlock; //定义一把自旋锁
//count自加操作 三条命令合并一条
int inc(int *value, int add)
{
int old;
__asm__ volatile
(
"lock;xaddl %2,%1" //xadd1 代表 2+1后将值赋值到1中 在此代码块中1代表value 2代表add
:"=a"(old) //a代表寄存器 m是内存
: "m" (*value), "a"(add) //代表在寄存器中将内存中的value值进行相加操作
: "cc", "memory" //cc:用于记录上一条指令执行的结果信息; memory:通过访问内存地址来读取或写入数据
);
return old;
}
void *thread_callback(void *arg)
{
int *count = (int *)arg;
int i = 0;
while (i ++ < 100000)
{
#if 0
(*count)++; //此程序中最重要的一行
#elif 0 //为0屏蔽代码块 类似于大段注释
pthread_mutex_lock(&mutex); //上锁
(*count)++;
pthread_mutex_unlock(&mutex); //下锁
#elif 0
pthread_spin_lock(&spinlock);
(*count)++;
pthread_spin_unlock(&spinlock);
#else
inc(count,1);
#endif
usleep(1); // 进程休眠1微秒
}
}
int main()
{
pthread_t threadid[THREAD_COUNT] = { 0 }; //定义线程数组 长度为宏定义的10 每个元素都是 pthread_t 类型的变量,{0}是初始化为0
pthread_mutex_init(&mutex ,NULL); //对线程锁的初始化
pthread_spin_init(&spinlock ,PTHREAD_PROCESS_SHARED); //对线程锁的初始化 第二个参数是代表进程共用
int i = 0;
int count = 0;
//创建10个线程
for (i = 0; i < THREAD_COUNT; i++)
{
//创建线程 并共用count参数
pthread_create(&threadid[i], NULL, thread_callback, &count);
}
for (i = 0; i < 100; i++)
{
printf("count: %d \n", count);
sleep(1);
}
}
课后了解 CAS技术