Простой кроссплатформенный прием - записать идентификатор процесса (pid) первого экземпляра в файл в известном месте (например, my_program.pid во системном временном каталоге). При каждом запуске проверяйте, существует ли этот файл. Если он существует, прочитайте pid и проверьте, запущен ли процесс. Если процесс все еще выполняется, выйдите. Если нет, продолжайте работу и запишите свой идентификатор процесса в файл. Когда программа, написавшая файл, завершает работу, она должна удалить файл.
Возможны условия гонки (например, работающая программа может завершить работу в короткий момент после проверки, но до того, как ваша программа решит выйти), но если вы не создаете приложение коммерческого уровня, это обычно хорошо достаточно.