UNIX Day15

1 并发冲突
2 基于互斥体的线程同步
3 基于信号量的线程同步
1 并发冲突
1.1 问题
当多个线程同时访问其共享的进程资源时,如果不能相互协调配合,就难免会出现数据不一致或不完整的问题。这种现象被称为线程间的并发访问冲突,简称并发冲突。

1.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:并发冲突

代码如下所示:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int g_cn = 0;
void* start_routine (void* arg)
{
int i;
for (i = 0; i <1000000; ++i)
++g_cn;_
return NULL;
}
int main()
{
pthread_t thread;
int error = pthread_create (&thread, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
pthread_t thread1;
error = pthread_create (&thread1, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
if (pthread_join (thread, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
if (pthread_join (thread1, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
printf("%d\n", g_cn);
return 0;
}
上述代码中,以下代码:

int g_cn = 0;
定义一个全局变量,用于计算两百万次循环的累加和。

上述代码中,以下代码:

void* start_routine (void* arg)
{
int i;
for (i = 0; i <1000000; ++i)
++g_cn;_
return NULL;
}
定义线程过程函数start_routine。该函数有一个参数,用于从主线程传递数据。该函数中,以下代码:

int i;
for (i = 0; i <1000000; ++i)
++g_cn;_
设置一个循环,循环一百万次,将全局变量g_cn累加一百万次。

上述代码中,以下代码:

pthread_t thread;

int error = pthread_create (&thread, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
使用函数pthread_create创建新线程1。

上述代码中,以下代码:

pthread_t thread1;
error = pthread_create (&thread1, NULL, start_routine, NULL);

if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
使用函数pthread_create创建新线程2。两个新线程分别对全局变量g_cn累加一百万次,由于并发冲突,造成累加的和小于两百万次。

上述代码中,以下代码:

if (pthread_join (thread, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
使用函数pthread_join等待线程1退出。

上述代码中,以下代码:

if (pthread_join (thread1, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
使用函数pthread_join等待线程2退出。

1.3 完整代码
本案例的完整代码如下所示:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int g_cn = 0;
void* start_routine (void* arg)
{
int i;
for (i = 0; i <1000000; ++i)
++g_cn;_
return NULL;
}
int main()
{
pthread_t thread;
int error = pthread_create (&thread, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
pthread_t thread1;
error = pthread_create (&thread1, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
if (pthread_join (thread, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
if (pthread_join (thread1, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
printf("%d\n", g_cn);
return 0;
}
2 基于互斥体的线程同步
2.1 问题
当多个线程同时访问其共享的进程资源时,如果不能相互协调配合,就难免会出现数据不一致或不完整的问题。这种现象被称为线程间的并发访问冲突,简称并发冲突。

2.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:基于互斥体的线程同步

代码如下所示:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
int g_cn = 0;
void* start_routine (void* arg)
{
int i;
for (i = 0; i <1000000; ++i)
{
pthread_mutex_lock (&g_mutex);
++g_cn;
pthread_mutex_unlock (&g_mutex);
}
return NULL;
}
int main()
{
pthread_mutex_init (&g_mutex, NULL);
pthread_t thread;
int error = pthread_create (&thread, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
pthread_t thread1;
error = pthread_create (&thread1, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
if (pthread_join (thread, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
if (pthread_join (thread1, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
pthread_mutex_destroy (&g_mutex);
printf("%d\n", g_cn);
return 0;
}
上述代码中,以下代码:

pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
定义互斥体g_mutex,并对其进行初始化。

上述代码中,以下代码:

int g_cn = 0;
定义一个全局变量,用于计算两百万次循环的累加和。

上述代码中,以下代码:

void* start_routine (void* arg)
{
int i;
for (i = 0; i <1000000; ++i)
{
pthread_mutex_lock (&g_mutex);
++g_cn;
pthread_mutex_unlock (&g_mutex);
}
return NULL;
}
定义线程过程函数start_routine。该函数有一个参数,用于从主线程传递数据。该函数中,以下代码:

    pthread_mutex_lock (&g_mutex);

使用函数pthread_mutex_lock锁定互斥体g_mutex。任何时刻只会有一个线程对特定的互斥体加锁成功,其它试图对其加锁的线程会在此函数的阻塞中等待,直到该互斥体的持有者线程将其解锁。该函数中,以下代码:

    ++g_cn;

对全局变量g_cn进行一次累加。该函数中,以下代码:

    pthread_mutex_unlock (&g_mutex);

使用函数pthread_mutex_unlock解锁互斥体g_mutex。对特定互斥体加锁成功的线程通过此函数将其解锁,那些阻塞于对该互斥体加锁的线程中的一个会被唤醒,得到该互斥体,并从pthread_mutex_lock函数中返回。该函数中,以下代码:

int i;
for (i = 0; i <1000000; ++i)
{
pthread_mutex_lock (&g_mutex);
++g_cn;
pthread_mutex_unlock (&g_mutex);
}
设置一个循环,循环一百万次,将全局变量g_cn采用互斥方法累加一百万次。

上述代码中,以下代码:

int main()
{
pthread_mutex_init (&g_mutex, NULL);
使用函数pthread_mutex_init初始化互斥体,该函数有两个参数,说明如下:

第一个参数为互斥体。

第二个参数为互斥体属性,同步一个进程内的多个线程,取NULL。

上述代码中,以下代码:

pthread_t thread;

int error = pthread_create (&thread, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
使用函数pthread_create创建新线程1。

上述代码中,以下代码:

pthread_t thread1;
error = pthread_create (&thread1, NULL, start_routine, NULL);

if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
使用函数pthread_create创建新线程2。两个新线程分别对全局变量g_cn累加一百万次,由于采用了互斥体技术避免并发冲突,造成累加的和等于两百万次。

上述代码中,以下代码:

if (pthread_join (thread, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
使用函数pthread_join等待线程1退出。

上述代码中,以下代码:

if (pthread_join (thread1, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
使用函数pthread_join等待线程2退出。

上述代码中,以下代码:

pthread_mutex_destroy (&g_mutex);

使用函数pthread_mutex_destroy销毁互斥体,释放和互斥体mutex有关的一切内核资源。

2.3 完整代码
本案例的完整代码如下所示:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
int g_cn = 0;
void* start_routine (void* arg)
{
int i;
for (i = 0; i <1000000; ++i)
{
pthread_mutex_lock (&g_mutex);
++g_cn;
pthread_mutex_unlock (&g_mutex);
}
return NULL;
}
int main()
{
pthread_mutex_init (&g_mutex, NULL);
pthread_t thread;
int error = pthread_create (&thread, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
pthread_t thread1;
error = pthread_create (&thread1, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
if (pthread_join (thread, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
if (pthread_join (thread1, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
pthread_mutex_destroy (&g_mutex);
printf("%d\n", g_cn);
return 0;
}
3 基于信号量的线程同步
3.1 问题
当多个线程同时访问其共享的进程资源时,如果不能相互协调配合,就难免会出现数据不一致或不完整的问题。这种现象被称为线程间的并发访问冲突,简称并发冲突。

3.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:基于信号量的线程同步

代码如下所示:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <semaphore.h>
sem_t g_sem;
int g_cn = 0;
void* start_routine (void* arg)
{
int i;
for (i = 0; i <1000000; ++i)
{
sem_wait (&g_sem);
++g_cn;
sem_post (&g_sem);
}
return NULL;
}
int main()
{
sem_init (&g_sem, 0, 1);
pthread_t thread;
int error = pthread_create (&thread, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
pthread_t thread1;
error = pthread_create (&thread1, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
if (pthread_join (thread, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
if (pthread_join (thread1, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
sem_destroy (&g_sem);
printf("%d\n", g_cn);
return 0;
}
上述代码中,以下代码:

sem_t g_sem;
定义信号量g_sem。

上述代码中,以下代码:

int g_cn = 0;
定义一个全局变量,用于计算两百万次循环的累加和。

上述代码中,以下代码:

void* start_routine (void* arg)
{
int i;
for (i = 0; i <1000000; ++i)
{
sem_wait (&g_sem);
++g_cn;
sem_post (&g_sem);
}
return NULL;
}
定义线程过程函数start_routine。该函数有一个参数,用于从主线程传递数据。该函数中,以下代码:

    sem_wait (&g_sem);

使用函数sem_wait等待信号量g_sem。若信号量计数器的值大于1,则将其减1并立即返回0,否则函数sem_wait函数会阻塞,直到信号量计数器的值够减时,将其减1并返回0。该函数中,以下代码:

    ++g_cn;

对全局变量g_cn进行一次累加。该函数中,以下代码:

    sem_post (&g_sem);

使用函数sem_post释放信号量g_sem。调用sem_post函数将直接导致sem信号量计数器的值加1。那些此刻正阻塞于针对该信号量的sem_wait函数调用的线程中的一个将被唤醒,令信号量g_sem计数器的值减1并从sem_wait函数中返回。该函数中,以下代码:

int i;
for (i = 0; i <1000000; ++i)
{
sem_wait (&g_sem);
++g_cn;
sem_post (&g_sem);
}
设置一个循环,循环一百万次,将全局变量g_cn采用互斥方法累加一百万次。

上述代码中,以下代码:

int main()
{
sem_init (&g_sem, 0, 1);
使用函数sem_init初始化信号量,该函数有三个参数,说明如下:

第一个参数为信号量。

第二个参数为0表示该信号量用于线程间的同步;非0表示该信号量用于进程间的同步。对于后者,信号量被存储在共享内存中。

第三个参数为信号量初值。

上述代码中,以下代码:

pthread_t thread;

int error = pthread_create (&thread, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
使用函数pthread_create创建新线程1。

上述代码中,以下代码:

pthread_t thread1;
error = pthread_create (&thread1, NULL, start_routine, NULL);

if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
使用函数pthread_create创建新线程2。两个新线程分别对全局变量g_cn累加一百万次,由于采用了互斥体技术避免并发冲突,造成累加的和等于两百万次。

上述代码中,以下代码:

if (pthread_join (thread, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
使用函数pthread_join等待线程1退出。

上述代码中,以下代码:

if (pthread_join (thread1, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
使用函数pthread_join等待线程2退出。

上述代码中,以下代码:

sem_destroy (&g_sem);

使用函数sem_destroy销毁信号量,释放和信号量sem有关的一切内核资源。

3.3 完整代码
本案例的完整代码如下所示:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <semaphore.h>
sem_t g_sem;
int g_cn = 0;
void* start_routine (void* arg)
{
int i;
for (i = 0; i <1000000; ++i)
{
sem_wait (&g_sem);
++g_cn;
sem_post (&g_sem);
}
return NULL;
}
int main()
{
sem_init (&g_sem, 0, 1);
int sval = 0;
sem_getvalue (&g_sem, &sval);
printf("%d\n", sval);
sleep(3);
pthread_t thread;
int error = pthread_create (&thread, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
pthread_t thread1;
error = pthread_create (&thread1, NULL, start_routine, NULL);
if (error)
{
printf (“pthread_create: %s\n”, strerror (error));
exit (EXIT_FAILURE);
}
if (pthread_join (thread, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
if (pthread_join (thread1, NULL))
{
perror (“pthread_join”);
exit (EXIT_FAILURE);
}
sem_destroy (&g_sem);
printf("%d\n", g_cn);
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值