本文共 4290 字,大约阅读时间需要 14 分钟。
同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。“同”字从字面上容易理解为一起动作,其实不是,“同”字应是指协同、协助、互相配合。
线程同步,可理解为线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给A;A再继续操作。
线程同步机制主要有:互斥量、信号量、条件变量、读写锁等。这篇文章先讲一下互斥量和信号量。
1. 互斥量
我们可以把互斥量想成一把锁。在访问共享资源前对互斥量进行加锁,在访问完后释放互斥量上的锁。 对互斥量进行加锁后,任何其他试图再对该互斥量加锁的线程都会被阻塞直到当前持有锁的线程释放锁。
互斥量有关的操作函数在头文件pthread.h中声明,主要有以下函数:
int pthread_mutex_init(pthread_mutex_t *restrict mutex, constpthread_mutexattr_t *restrict attr); //初始化互斥量
int pthread_mutex_destroy(pthread_mutex_t *mutex); //回收非配给该互斥量的资源
int pthread_mutex_lock(pthread_mutex_t *mutex); //对互斥量加锁
int pthread_mutex_trylock(pthread_mutex_t *mutex); //尝试加锁
int pthread_mutex_unlock(pthread_mutex_t *mutex); //释放加在互斥量上的锁
如果不希望线程被阻塞可以使用pthread_mutex_trylock尝试对互斥量进行加锁。如果此时互斥量未被加锁,那么pthread_mutex_trylock将锁住互斥量,否则pthread_mutex_trylock就会失败,不能锁住互斥量,返回EBUSY。
互斥量的使用代码如下:
#include
#include
#include
#include
pthread_mutex_t mutex;
int count = 0;
char msg_buf[64];
void SetMsg_Func(void);
void PrintMsg_Func(void);
int main()
{
intret;
pthread_tset_thread;
count= 4;
pthread_mutex_init(&mutex,NULL);//初始化互斥量
ret= pthread_create(&set_thread, NULL, (void *)&SetMsg_Func, NULL);//创建线程
if(ret!= 0)
{
perror("ThreadCreate Failed!");
exit(EXIT_FAILURE);
}
PrintMsg_Func();
ret= pthread_join(set_thread, NULL);//设置主线程等待新创建的线程结束
if(ret!= 0)
{
perror("ThreadJoin Failed!");
exit(EXIT_FAILURE);
}
printf("Finished!\n");
pthread_mutex_destroy(&mutex);//释放互斥量
return0;
}
void SetMsg_Func(void)
{
while(count > 0)
{
pthread_mutex_lock(&mutex);//互斥量加锁
memset(msg_buf,0, 64);
sprintf(msg_buf,"count=%d.\n", count--);
pthread_mutex_unlock(&mutex);//互斥量解锁
srand((int)time(0));
sleep(rand()%3);
}
pthread_exit(0);
}
void PrintMsg_Func(void)
{
while(count >= 0 )
{
pthread_mutex_lock(&mutex);//互斥量加锁
printf(msg_buf);
pthread_mutex_unlock(&mutex);//互斥量解锁
if(0==count )
{
break;
}
srand((int)time(0));
sleep(rand()%3);
}
}
执行结果:
count=4.
count=4.
count=3.
count=2.
count=1.
Finished!
2.信号量
信号量本质上是一个非负的证书计数器,只有当信号量的值大于0时,才能使用公共资源,否则说明没有可用资源。信号量时可以公有的,也可以是私有的,公有信号量在进程内存中分配,并进行初始化。公有信号量可能供多个进程使用,具体取决于信号的分配和初始化的方式。私有信号量只能被本进程中的线程使用。
多线程信号量的数据结构为sem_t,与信号量有关的操作函数在头文件semaphore.h中声明,主要有:
int sem_init(sem_t *sem,int pshared,unsigned int value);
int sem_destroy(sem_t *sem);
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_post(sem_t *sem);
int sem_getvalue(sem_t *sem);
sem_init() 初始化一个定位在 sem 的匿名信号量。value 参数指定信号量的初始值。 pshared 参数指明信号量是由进程内线程共享,还是由进程之间共享。如果 pshared 的值为 0,那么信号量将被进程内的线程共享,并且应该放置在这个进程的所有线程都可见的地址上(如全局变量,或者堆上动态分配的变量)。如果 pshared 是非零值,那么信号量将在进程之间共享,并且应该定位共享内存区域(见 shm_open(3)、mmap(2) 和 shmget(2))。因为通过 fork(2) 创建的孩子继承其父亲的内存映射,因此它也可以见到这个信号量。所有可以访问共享内存区域的进程都可以用 sem_post(3)、sem_wait(3) 等等操作信号量。初始化一个已经初始的信号量其结果未定义。
sem_init() 成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值。
sem_wait() 减小(锁定)由sem指定的信号量的值.如果信号量的值比0大,那么进行减一的操作,函数立即返回。如果信号量当前为0值,那么调用就会一直阻塞直到或者是信号量变得可以进行减一的操作(例如,信号量的值比0大),或者是信号处理程序中断调用。
sem_post(sem_t*sem):该函数用于以原子操作的方式将信号量的值加1。用来增加信号量的值当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不再阻塞,选择机制同样是由线程的调度策略决定的。它信号量的值加1同时发出信号来唤醒等待的线程。
sem_destroy:该函数用于对用完的信号量的清理。用来释放信号量sem。
信号量使用代码如下:
#include
#include
#include
#include
#include
#include
void *thread_function(void *arg);
sem_t bin_sem;
#define WORK_SIZE 1024 charwork_area[WORK_SIZE]; /* 用来存放输入内容 */
int main()
{
intres; /* 暂存一些命令的返回结果 */
pthread_ta_thread; /* 织带新建的线程 */
void*thread_result; /* 存放线程处理结果 */
res= sem_init(&bin_sem, 0, 0); /* 初始化信号量,并且设置初始值为0*/
if(res != 0)
{
perror("Semaphoreinitialization failed");
exit(EXIT_FAILURE);
}
res= pthread_create(&a_thread, NULL, thread_function, NULL); /* 创建新线程 */
if(res != 0)
{
perror("Threadcreation failed");
exit(EXIT_FAILURE);
}
printf("Inoutsome text, Enter 'end' to finish\n");
while(strncmp("end",work_area, 3) != 0)
{
/*当工作区内不是以end开头的字符串时...*/
fgets(work_area,WORK_SIZE, stdin); /* 从标准输入获取输入到worl_area */
sem_post(&bin_sem);/* 信号量+1 */
}
printf("\nWaitingfor thread to finish...\n");
res= pthread_join(a_thread, &thread_result); /* 等待线程结束 */
if(res != 0)
{
perror("Threadjoin failed");
exit(EXIT_FAILURE);
}
printf("Threadjoined\n");
sem_destroy(&bin_sem);/* 销毁信号量 */
exit(EXIT_SUCCESS);
}
void *thread_function(void *arg)
{
sem_wait(&bin_sem);/* 等待信号量有大于0的值然后-1 */
while(strncmp("end",work_area, 3) != 0)
{
printf("Youinput %ld characters\n", strlen(work_area)-1); /* 获取输入字符串长度 8*/
sem_wait(&bin_sem);/* 等待信号量有大于0的值然后-1 */
}
pthread_exit(NULL);
}
转载地址:https://blog.csdn.net/weixin_33826897/article/details/113903139 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!