CRITICAL_SECTION (MSDN) in Windows can be used for thread synchronization. Essentially you can create a variable and limit it’s ownership to one thread at a time. Something like this
CRITICAL_SECTION cs;
volatile long counter = 0;
int main(){
InitializeCriticalSection(&cs);
//Create threads and run thread_func
//.....
//.....
}
void thread_func (){
//Get ownership of counter
EnterCriticalSection(&cs);
//Increment counter
counter++;
printf("No. of threads run: %d\n", counter);
//Leave ownership of counter
//so that other threads can have it
LeaveCriticalSection(&cs);
}
Threads block while waiting for ownership of counter . So only one thread will have access to counter at a time.
Earlier we have created a TCP server using winsock (https://jijnasu.in/c-tcp-server-in-windows-thread-per-connection/). Let’s make use of CRITICAL_SECTION to count the number of requests served by our server.
#include <winsock.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#define PORT 50001
//Function that threads run
static DWORD __stdcall func(int s);
//Function to set no. of req served
static void __stdcall inc();
//CRITICAL_SECTION variable
CRITICAL_SECTION cs;
/*
(long counter) to count the
number of requests served.
Volatile so that the
value is read from memory
and not cache
(I think so)
*/
volatile long counter = 0;
int main() {
//Dont ask just put it in there
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
fprintf(stderr, "WSAStartup failed.\n");
exit(1);
}
//Socket initiation
int sock;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
printf("Socket initiation failed!");
return 0;
}
//Socket settings
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(addr.sin_zero, '\0', sizeof addr.sin_zero);
//Bind the socket
int b;
if ((b = bind(sock, &addr, sizeof(addr))) == SOCKET_ERROR) {
printf("Socket initiation failed!");
return 0;
}
//Listen on socket
int l = listen(sock, 25);
//Initialize CRITICAL_SECTION
InitializeCriticalSection(&cs);
printf("TCP server listening on port %d\n", PORT);
//If (con) pass it to a new thread
while (1) {
struct sockaddr_in client_addr;
unsigned int c_len = sizeof client_addr;
int s1 = accept(sock, &client_addr, &c_len);
unsigned int cur_tid;
_beginthreadex(NULL, 0, func, s1, 0, &cur_tid);
}
//Cleanup
closesocket(sock);
WSACleanup();
return 0;
}
static DWORD __stdcall func(int s) {
puts("Connection accepted");
//Read data from client
char buff[1024];
unsigned int tot_bytes = recv(s, buff, sizeof(buff), MSG_PEEK);
char * client_data = (char *)malloc(tot_bytes + 1);
for (int i = 0; i < (tot_bytes); i++) {
client_data[i] = buff[i];
}
client_data[tot_bytes] = '\0';
printf("Msg from client: %s\n", client_data);
//Pretend you are processing info
puts("Processing req");
Sleep(5000);
puts("Processing complete");
//Prepare message for the client
char * message;
if (strcmp(client_data, "COMMAND1") == 0) {
char lmsg[] = "COMMAND1 recieved";
message = (char *)malloc(strlen(lmsg));
message = lmsg;
}
else if (strcmp(client_data, "COMMAND2") == 0) {
char lmsg[] = "COMMAND2 recieved";
message = (char *)malloc(strlen(lmsg));
message = lmsg;
}
else {
char lmsg[] = "NO COMMAND recieved";
message = (char *)malloc(strlen(lmsg));
message = lmsg;
}
free(client_data);
//Send data to client
send(s, message, strlen(message), 0);
inc();
return 0;
}
static void __stdcall inc() {
EnterCriticalSection(&cs);
counter++;
printf("No. of reqs served: %d\n", counter);
LeaveCriticalSection(&cs);
}