My Shiny Weblog!

programming, photography and lifestyle

Ако чиновниците бяха процеси

Още от гимназията съм чел и знам за проблема с обядващите философи. Много добре знам, че има проблеми при синхронизацията на няколко нишки. Въпреки това, смело започнах да пиша една програма, която ползва две нишки. Бях напълно сигурен, че няма никаква вероятност да оплескам нещата, защото това което правя е абсолютно просто нещо. И както винаги става в такива случай – нещата се оплескаха. Направих най-класическата мъртва хватка в програмирането. Както казваше един преподавател – “учебникарски пример”. В едната нишка заключвам един ресурс и чакам за втория. В другата нишка заключвам втория и чакам за първия. Естествено в програмата, която пиша това не е толкова лесно забележимо и хич не е лесно да направиш извод, че точно това се случва. Добре, че го видях в сорс кода, още преди да съм започнал да тествам програмата. Иначе сигурно щях да си блъскам главата поне няколко часа. В Интернет е пълно с примери описващи най-различни аспекти на този проблем, както и възможни решения, техники и т.н. Аз все пак реших да си напиша една програмка, която да илюстрира какво аз успях да оплескам в случая. Ако спести главоболията поне на един човек, значи си струва.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>
#include <pthread.h>

static flag = 0;
static pthread_mutex_t mutex_a = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mutex_b = PTHREAD_MUTEX_INITIALIZER;

static void *thread_a(void *tmp)
{
   while(1)
   {
      pthread_mutex_lock(&mutex_a);
      printf("thread_a: from mutex_a critical section\n");
      pthread_mutex_lock(&mutex_b);
      printf("thread_a: from mutex_b critical section\n");
      flag = 1;
      pthread_mutex_unlock(&mutex_b);
      pthread_mutex_unlock(&mutex_a);
   }
}

static void *thread_b(void *tmp)
{
   while(1)
   {
      pthread_mutex_lock(&mutex_b);
      printf("thread_b: from mutex_b critical section\n");
      if (flag)
      {
         pthread_mutex_lock(&mutex_a);
         printf("thread_a: from mutex_a critical section\n");
         pthread_mutex_unlock(&mutex_a);
         flag = 0;
      }
      pthread_mutex_unlock(&mutex_b);
   }
}

int main()
{
   pthread_t a, b, c;
   pthread_create(&a, NULL, thread_a, (void *)NULL);
   pthread_create(&b, NULL, thread_b, (void *)NULL);
   pthread_join(a, (void *)NULL);
}